2017-10-30 20 views
0

SurfaceView、TextureViewでいくつかの機能をテストするためにCamera1 APIを使用しています。 bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);で作成onPictureTakenメソッドのビットマップがガベージコレクトされていません

ビットマップがリサイクルされることはありませんし、メモリはbitmap.recycle()System.gc()が呼ばれていても戻って主張されることはありません。

ビットマップのリサイクルに関するいくつかのスレッドはありますが、どれも動作しません。

  • Memory usage does not decrease even I recycle bitmaps
  • この

  • Recycling Bitmap does not free memory
    1. は、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ファイルを作成する方法もありますか?

      Memory Profiler of the image saving processMemory Profile 2

      IはまたCamera2 Apiコードをテストします。ここにこのコードのメモリプロファイルがあります。

      Memory Profiler Camera2 Api 破線は、鋸歯状のパターンを持つオブジェクト割り当てで、エッジにGC'edされたオブジェクトですが、すべてのメモリは安定しており、オブジェクト割り当てパターンに従っていません。これはどのように可能ですか?

    答えて

    0

    私はこの問題を早期に発見しましたが、なぜこれが起こるのかわかりませんが、本当に心配するべきではないと思います。

    recycleメソッドのドキュメントでは、このメソッドが呼び出された直後にビットマップリソースが解放されるとは限りません。

    なぜ心配するべきでないのか説明するために、メモリに新しいイメージを割り当てるときにメモリが解放されます。新しい写真を撮り、メモリをチェックしてみると、メモリは追加されません。それとも、さらに5枚の写真を撮ろうとすると、新しいビットマップを作成するときにメモリが解放されるので、5枚の画像のメモリが取られないことがわかります。

    関連する問題