我正在使用Camera1 Api使用SurfaceView,TextureView测试一些功能。
使用bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
创建的位图永远不会被回收,即使调用了bitmap.recycle()
和System.gc()
,也永远无法回复内存。
以下是关于回收Bitmap的几个主题,但它们都不起作用。
这是我使用SurfaceView的代码,图像为4160,高度为3120,返回的位图大约为50mb。
CameraActivity
public class CameraActivity extends Activity {
private static final String SAVE_DIR = "Folder";
private Camera mCamera;
private FrameLayout preview;
private CameraPreview mPreview;
public static final int MEDIA_TYPE_IMAGE = 1;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Create an instance of Camera
if (checkCameraHardware(this)) {
mCamera = getCameraInstance();
}
if (mCamera == null) {
Toast.makeText(this, "Camera null ", Toast.LENGTH_SHORT).show();
return;
}
// Create our Preview view and set it as the content of our activity.
mPreview = new CameraPreview(this, mCamera);
preview = (FrameLayout) findViewById(R.id.camera_preview);
preview.addView(mPreview);
Button captureButton = (Button) findViewById(R.id.button_capture);
captureButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// get an image from the camera
mCamera.takePicture(null, null, mPicture);
}
});
}
/**
* Check if this device has a camera
*/
private boolean checkCameraHardware(Context context) {
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
// this device has a camera
return true;
} else {
// no camera on this device
return false;
}
}
/**
* A safe way to get an instance of the Camera object.
*/
public Camera getCameraInstance() {
Camera c = null;
try {
c = Camera.open(); // attempt to get a Camera instance
setCameraDisplayOrientation(this, CameraInfo.CAMERA_FACING_BACK, c);
} catch (Exception e) {
// Camera is not available (in use or does not exist)
}
return c; // returns null if camera is unavailable
}
public void setCameraDisplayOrientation(Activity activity, int cameraId, android.hardware.Camera camera) {
android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(cameraId, info);
int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
int orientation = getResources().getConfiguration().orientation;
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0:
degrees = 0;
break;
case Surface.ROTATION_90:
degrees = 90;
break;
case Surface.ROTATION_180:
degrees = 180;
break;
case Surface.ROTATION_270:
degrees = 270;
break;
}
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
}
camera.setDisplayOrientation(result);
Camera.Parameters params = camera.getParameters();
params.setRotation(90);
camera.setParameters(params);
}
private PictureCallback mPicture = new PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
long startTime = System.currentTimeMillis();
File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
FileOutputStream fos = null;
Bitmap bitmap = null;
if (pictureFile == null) {
return;
}
try {
fos = new FileOutputStream(pictureFile);
bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
bitmap.compress(CompressFormat.JPEG, 100, fos);
} catch (FileNotFoundException e) {
System.out.println("CameraActivityonPictureTaken() File not found: " + e.getMessage());
} finally {
try {
if (fos != null) {
fos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
fos = null;
pictureFile = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
System.out.println("CameraActivity onPictureTaken() Bitmap recycled: " + bitmap.isRecycled() + ", size: " + bitmap.getAllocationByteCount() / (1024) + "kb");
}
bitmap.recycle();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
System.out.println("CameraSurfaceTextureListener onPictureTaken() Bitmap recycled: " + bitmap.isRecycled() + ", size: " + bitmap.getAllocationByteCount() / (1024) + "kb");
}
bitmap = null;
System.gc();
long finishTime = System.currentTimeMillis();
System.out.println("CameraActivity onPictureTaken() TIME: " + (finishTime - startTime) + "ms");
mPreview.refreshPreview();
}
}
};
/**
* Create a File for saving an image or video
*/
private File getOutputMediaFile(int type) {
// To be safe, you should check that the SDCard is mounted
// using Environment.getExternalStorageState() before doing this.
File mediaStorageDir = new File(Environment.getExternalStorageDirectory(), "MyCameraApp");
// This location works best if you want the created images to be shared
// between applications and persist after your app has been uninstalled.
// Create the storage directory if it does not exist
if (!mediaStorageDir.exists()) {
if (!mediaStorageDir.mkdirs()) {
Log.d("MyCameraApp", "failed to create directory");
return null;
}
}
// Create a media file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
File mediaFile;
if (type == MEDIA_TYPE_IMAGE) {
mediaFile = new File(mediaStorageDir.getPath() + File.separator + "IMG_" + timeStamp + ".jpg");
} else {
return null;
}
return mediaFile;
}
@Override
protected void onPause() {
super.onPause();
releaseCamera(); // release the camera immediately on pause event
if (preview != null && mPreview != null) {
preview.removeView(mPreview);
mPreview = null;
}
}
@Override
protected void onResume() {
super.onResume();
// Create an instance of Camera
if (checkCameraHardware(this)) {
if (mCamera == null) {
mCamera = getCameraInstance();
System.out.println("onResume() mCamera: " + mCamera);
if (mPreview == null) {
// Create our Preview view and set it as the content of our
// activity.
mPreview = new CameraPreview(this, mCamera);
System.out.println("onResume() preview child count: " + preview.getChildCount());
preview.removeAllViews();
preview.addView(mPreview);
} else {
mPreview.refreshPreview();
}
}
}
}
private void releaseCamera() {
if (mCamera != null) {
mCamera.release(); // release the camera for other applications
mCamera = null;
}
}
}
这是图像保存过程的Memory Profiler。应用程序在运行相机预览时使用16 MB RAM。当我触摸按钮保存图像时,它保存时上升到110mb,它在大约25.00s开始,我没有使用线程在视觉上检查,应用程序在保存时冻结,然后它减少到75 mb并保持在这个水平如果我不使用主页按钮手动GC或暂停应用程序。我在43.00s手动GC。我打开应用程序,7分钟后Bitmap仍然没有被垃圾回收。我还检查了CameraKit app和CameraView,拍摄照片后它们也没有GC。有没有办法手动从Bitmap声明内存。
如何检查Activity是否与新的Memory Profiler泄漏并创建.hprof文件?
我还测试Camera2 Api代码。以下是此代码的内存配置文件。
答案 0 :(得分:0)
我之前也发现了这个问题,我不知道为什么会这样,但我认为你不应该为此担心。
由于recycle
方法的文档说不能保证在调用此方法后立即释放位图资源。
要解释为什么您不必担心,当您尝试在内存中分配新图像时,将释放内存。尝试拍摄新照片并检查内存,不会添加内存。或者甚至更好,尝试拍摄5张照片,你会发现它不会占用5张图像的内存,因为在创建新的Bitmap时会释放内存。