SurfaceView、TextureViewでいくつかの機能をテストするためにCamera1 APIを使用しています。 bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
で作成onPictureTakenメソッドのビットマップがガベージコレクトされていません
ビットマップがリサイクルされることはありませんし、メモリはbitmap.recycle()
とSystem.gc()
が呼ばれていても戻って主張されることはありません。
ビットマップのリサイクルに関するいくつかのスレッドはありますが、どれも動作しません。
この
-
は、50メガバイト程度のビットマップを返し、私は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.00秒でGCしました。私はアプリを開いたままにして、Bitmapはまだ7分後にガベージコレクションされませんでした。私もCameraKitアプリとCameraViewをチェックしましたが、写真を撮影した後にGC'edされません。ビットマップから手動でメモリを要求する方法はありません。
新しいメモリプロファイラでアクティビティがリークしているかどうかを確認し、.hprofファイルを作成する方法もありますか?
IはまたCamera2 Apiコードをテストします。ここにこのコードのメモリプロファイルがあります。
破線は、鋸歯状のパターンを持つオブジェクト割り当てで、エッジにGC'edされたオブジェクトですが、すべてのメモリは安定しており、オブジェクト割り当てパターンに従っていません。これはどのように可能ですか?