마스터Q&A 안드로이드는 안드로이드 개발자들의 질문과 답변을 위한 지식 커뮤니티 사이트입니다. 안드로이드펍에서 운영하고 있습니다. [사용법, 운영진]

안드로이드 사진촬영후 비트맵프리뷰 생성에서 메모리누수현상

0 추천

안녕하세요 이제 막안드로이드 개발을 시작한 초보 입니다.

현재 앱을 하나 만들고 있는데 카메라 사진촬영후 프리뷰 만드는 과정에서 메모리 누수현상이 발생하여 앱이 종료됩니다.

메모리 누수현상이 발생하는 순서는 아래와 같습니다.

1. 사진촬영

2. 사진저장

3. 사진활영

4. App종료

 

 

아래는 오류 내용입니다.

    Process: com.example.issue_camera9, PID: 18610
    java.lang.OutOfMemoryError
            at android.graphics.Bitmap.nativeCreate(Native Method)
            at android.graphics.Bitmap.createBitmap(Bitmap.java:928)
            at android.graphics.Bitmap.createBitmap(Bitmap.java:901)
            at android.graphics.Bitmap.createBitmap(Bitmap.java:833)
            at com.example.issue_camera9.SurfaceCamera.Preview$2.onPictureTaken(Preview.java:299)
            at android.hardware.Camera$EventHandler.handleMessage(Camera.java:987)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:146)
            at android.app.ActivityThread.main(ActivityThread.java:5602)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:515)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1283)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1099)
            at dalvik.system.NativeStart.main(Native Method)

 

Previw.java

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        Log.d(TAG,  "surfaceDestroyed1");
        if (mCamera != null) {
            mCamera.stopPreview();
            mCamera.release();
            mCamera = null;
            Log.d(TAG,  "surfaceDestroyed");
        }
    }

위부분은 카메라에서 나가면 카메라를 종료시키는 부분입니다.

public void PressTakePicture() {
	if (mIsTakingPhoto) {
		return;
	}
	mCamera.startPreview();
	Camera.PictureCallback jpegPictureCallback = new Camera.PictureCallback() {
		@Override
		public void onPictureTaken(byte[] data, Camera camera) {
			int maxSize = 2048;
			mCamera.stopPreview();
			BitmapFactory.Options options = new BitmapFactory.Options();
			options.inJustDecodeBounds = true;
			BitmapFactory.decodeByteArray(data, 0, data.length, options);
			int width = options.outWidth;
			int height = options.outHeight;
			int srcSize = Math.max(width, height);
			options.inSampleSize = maxSize < srcSize ? (srcSize / maxSize) : 1;
			options.inJustDecodeBounds = false;
			Bitmap tmp = BitmapFactory.decodeByteArray(data, 0, data.length, options);
			int size = Math.min(options.outWidth, options.outHeight);
			float previewRatio = (float) mSurfaceSize.height / (float) mSurfaceSize.width;
			float cameraRatio = (float) options.outHeight / (float) options.outWidth;
			Matrix matrix = new Matrix();
			matrix.postRotate(90);
			int length = (int) (size * (previewRatio / cameraRatio));
			int rid = size - length;
			Bitmap source = Bitmap.createBitmap(tmp,
					0,  // x
					(int) (rid * 0.5), // y
					length,
					length,
					matrix, true);
			tmp.recycle();

			Log.d(TAG,  "PressTakePicture (int) (rid * 0.5) : " + (int) (rid * 0.5));
			Log.d(TAG,  "PressTakePicture length : " + length);
			Log.d(TAG,  "PressTakePicture matrix : " + matrix);
			BusHolder.getInstance().post(new TakePicture(source));
			mIsTakingPhoto = false;
		}
	};

	Camera.ShutterCallback shutterCallback = new Camera.ShutterCallback() {
		@Override
		public void onShutter() {
		}
	};

	try {
		mCamera.takePicture(shutterCallback, null, jpegPictureCallback);
		mIsTakingPhoto = true;
	} catch (Exception e) {
		e.printStackTrace();
	}
}

최초로 비트맵 이미지를 만는 곳입니다.

 

MainActivity.java

 Button.OnClickListener mClickListener = new View.OnClickListener() {
                        public void onClick(View v) {
                            switch (v.getId()) {
                                case R.id.picture_save_button:
                                    mCurrentMode = MODE_CAMERA_PREVIEW;
                                    mSquaredView.setImageBitmap(null);
                                    SaveBitmapToFile();
                    mPreview.retake();
                    findViewById(R.id.picture_save_button).setVisibility(View.GONE);
                    break;
            }
        }
    };

    private void SaveBitmapToFile() {
        File picFile = getOutputMediaFile();
        try {
            FileOutputStream fos = new FileOutputStream(picFile);
            if (mBitmap != null) {
                mBitmap.compress(Bitmap.CompressFormat.JPEG, 80, fos);
            }
            fos.close();
            if (mBitmap != null) {
                mBitmap.recycle();
                Log.d(TAG, "recycle");
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private File getOutputMediaFile() {
        File mediaStorageDir = new File(
                Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM),
                "issue_camera9"
        );

        if (!mediaStorageDir.exists()) {
            if (!mediaStorageDir.mkdirs()) {
                Log.d(TAG, "failed to create directory");
                return null;
            }
        }

        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
        File mediaFile;
        Log.d(TAG, "getOutputMediaFile : "+mediaStorageDir.getPath() + File.separator
                + JPEG_FILE_PREFIX + timeStamp + JPEG_FILE_SUFFIX);
        mediaFile = new File(
                mediaStorageDir.getPath() + File.separator
                        + JPEG_FILE_PREFIX + timeStamp + JPEG_FILE_SUFFIX
        );

        return mediaFile;
    }

위부분은 사진촬영후 사진저장버튼을 누르면 이미지파일을 저장하는 코드입니다.

 

여기까지 읽어주셔서 감사합니다.

살별패 (180 포인트) 님이 2015년 2월 13일 질문
Preview.java:299 여긴 어딘가요?

2개의 답변

+2 추천
일단 메니페스트에 이거부터 넣어봐요

android:largeHeap="true"
익명사용자 님이 2015년 2월 13일 답변
해결했습니다.
조언 감사합니다!!
+2 추천
maxSize 가 2048 인데

ARGB8888 같은 경우 2048 X 2048 X 4 = 16.7MB 입니다.

createBimap 에서 OOM 이 발생하였으므로

포맷을 ARGB8888 에서 RGB565 로 바꾸시든지

inSampleSize 를 확 늘려서 작은 사이즈의 비트맵을 만드는 방법이 있겠네요
mamondebaltob (32,750 포인트) 님이 2015년 2월 13일 답변
해결했습니다.
조언 감사합니다~!!
...