SurfaceView, TextureView로 일부 기능을 테스트하기 위해 Camera1 API를 사용하고 있습니다.onPictureTaken 메서드의 비트 맵이 가비지 수집되지 않습니다.
bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
으로 만든 비트 맵은 절대로 재활용되지 않으며 bitmap.recycle()
및 System.gc()
이 호출 되더라도 메모리가 다시 청구되지 않습니다.
다음은 Bitmap을 재활용하는 몇 가지 실책입니다.
이
-
는 50MB의 비트 맵을 반환 나 4160로 이미지와 함께 사용 서피스 뷰 SurfaceView 코드, 높이 3120이다.
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;
}
}
}
이 이미지 저장 프로세스의 메모리 프로파일 러입니다. 앱에서 카메라 미리보기를 실행하는 동안 16MB RAM을 사용 중입니다. 저장하는 동안 버튼을 터치하면 저장하는 동안 110MB까지 올라갑니다. 약 25.00 초에서 시작합니다. 시각적으로 확인하기 위해 스레드를 사용하지 않고 저장 중에 앱이 멈 추면 75MB로 줄어들어이 수준으로 유지됩니다. 수동으로 GC를하지 않거나 집 버튼을 사용하여 앱을 일시 중지하지 않은 경우 나는 43시에 GC'ed했다. 나는 앱을 열어두고 비트 맵은 7 분 후에도 가비지 수집되지 않았습니다. 또한 CameraKit 앱과 CameraView을 확인했지만 사진을 찍은 후에도 GC'ed되지 않았습니다. 비트 맵에서 수동으로 메모리를 요청할 방법이 없습니까?
새 Memory Profiler로 활동이 누출되고 .hprof 파일을 만들 수 있는지 어떻게 확인할 수 있습니까?
나는 또한 테스트 Camera2 Api 코드
. 다음은이 코드의 메모리 프로파일입니다. 점선은 톱니 모양 패턴을 가지며 가장자리에 GC'ed 개체가 있지만 모든 메모리는 안정적이며 개체 할당 패턴을 따르지 않습니다. 이것이 어떻게 가능한지?