2017-10-30 1 views
0

SurfaceView, TextureView로 일부 기능을 테스트하기 위해 Camera1 API를 사용하고 있습니다.onPictureTaken 메서드의 비트 맵이 가비지 수집되지 않습니다.

bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);으로 만든 비트 맵은 절대로 재활용되지 않으며 bitmap.recycle()System.gc()이 호출 되더라도 메모리가 다시 청구되지 않습니다.

다음은 Bitmap을 재활용하는 몇 가지 실책입니다.

  • Memory usage does not decrease even I recycle bitmaps
  • Recycling Bitmap does not free memory
    1. 는 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 파일을 만들 수 있는지 어떻게 확인할 수 있습니까? Memory Profile 2

      나는 또한 테스트 Camera2 Api 코드

      Memory Profiler of the image saving process

      . 다음은이 코드의 메모리 프로파일입니다. Memory Profiler Camera2 Api 점선은 톱니 모양 패턴을 가지며 가장자리에 GC'ed 개체가 있지만 모든 메모리는 안정적이며 개체 할당 패턴을 따르지 않습니다. 이것이 어떻게 가능한지?

    답변

    0

    나는 또한이 문제를 더 일찍 발견했는데 왜 이런 일이 일어날 지 모르지만 나는 그것에 대해 정말로 걱정하면 안된다고 생각합니다.

    recycle 메서드의 설명서에이 메서드가 호출 된 후 비트 맵 리소스가 해제되는 즉시 보장되지 않는다고 나와 있습니다.

    걱정하지 않아야하는 이유를 설명하기 위해 메모리에 새 이미지를 할당하려고하면 메모리가 비워집니다. 새 사진을 찍고 메모리를 확인하면 메모리가 추가되지 않습니다. 또는 더 좋게도 5 장의 사진을 찍으십시오. 새로운 비트 맵을 만들 때 메모리가 비워 짐에 따라 5 장의 이미지에 대한 메모리가 필요하지 않습니다.

    관련 문제