Android : Bitmap recycle ()은 어떻게 작동합니까?


89

다음과 같은 비트 맵 객체에 이미지를로드했다고 가정 해 보겠습니다.

Bitmap myBitmap = BitmapFactory.decodeFile(myFile);

이제 다음과 같은 다른 비트 맵을로드하면 어떻게 되나요?

myBitmap = BitmapFactory.decodeFile(myFile2);

첫 번째 myBitmap은 어떻게 되나요? 가비지 수집을 받거나 다른 비트 맵을로드하기 전에 수동으로 가비지 수집해야합니까? myBitmap.recycle()?

또한 큰 이미지를로드하고 도중에 재활용하면서 차례로 표시하는 더 좋은 방법이 있습니까?

답변:


79

첫 번째 비트 맵은 두 번째 비트 맵 을 디코딩 할 때 가비지 수집 되지 않습니다 . Garbage Collector 는 나중에 결정할 때마다이를 수행합니다. 최대한 빨리 메모리를 확보 recycle()하려면 두 번째 비트 맵을 디코딩하기 직전에 호출해야합니다 .

정말 큰 이미지를로드하려면 리샘플링해야합니다. 다음은 예입니다. 이미지를 Bitmap 객체로로드하는 동안 이상한 메모리 부족 문제가 발생했습니다 .


23

문제는 이것이 있다고 생각합니다. Android의 Honeycomb 이전 버전에서 실제 원시 비트 맵 데이터는 VM 메모리에 저장되지 않고 대신 기본 메모리에 저장됩니다. 이 네이티브 메모리 해당 자바 Bitmap객체가 GC 일 때 해제됩니다 .

그러나 네이티브 메모리가 부족하면 dalvik GC가 트리거되지 않으므로 앱에서 자바 메모리를 거의 사용하지 않을 수 있으므로 dalvik GC가 호출되지 않지만 비트 맵에 많은 네이티브 메모리를 사용합니다. 결국 OOM 오류가 발생합니다.

적어도 그것은 내 추측이다. 고맙게도 Honeycomb 이상에서는 모든 비트 맵 데이터가 VM에 저장되므로 전혀 사용할 필요가 없습니다 recycle(). 그러나 수백만 명의 사용자 (조각화 가 주먹을 흔드는 경우 )의 경우 recycle()가능한 한 사용해야 합니다 (엄청난 번거 로움). 또는 대신 GC를 호출 할 수 있습니다.


21

다음 이미지를로드하기 전에 myBitmap.recycle ()을 호출해야합니다.

myFile의 소스에 따라 (예 : 원본 크기를 제어 할 수없는 경우) 단순히 임의의 숫자를 리샘플링하는 대신 이미지를로드 할 때 이미지를 디스플레이 크기에 맞게 조정해야합니다.

if (myBitmap != null) {
    myBitmap.recycle();
    myBitmap = null;
}
Bitmap original = BitmapFactory.decodeFile(myFile);
myBitmap = Bitmap.createScaledBitmap(original, displayWidth, displayHeight, true);
if (original != myBitmap)
    original.recycle();
original = null;

내 활동을 시작할 때 초기화 한 정적에 displayWidth 및 displayHeight를 캐시합니다.

Display display = getWindowManager().getDefaultDisplay();
displayWidth = display.getWidth();
displayHeight = display.getHeight();

3
recycle ()을 호출 할 필요는 없습니다. 메모리를 즉시 해제하려면 좋은 생각입니다.
Karu

13
허용되는 대답은 "가능한 한 빨리 메모리를 해제하려면 recycle ()을 호출해야합니다"라고 말합니다. 귀하의 답변은 "myBitmap.recycle ()을 호출해야합니다"라고 말합니다. "should"와 "need to"에는 차이가 있으며이 경우 후자는 올바르지 않습니다.
Karu

1
맥락이 중요합니다. 질문은 "또한 큰 이미지를로드하고 도중에 재활용을 차례로 표시하는 더 좋은 방법이 있습니다"였습니다.
djunod

3
Android 4.1부터는 createScaledBitmap이 경우에 따라 원본과 동일한 인스턴스를 반환 할 수 있으므로 위의 예제가 중단 될 수 있습니다. 즉, 원본을 재활용하기 전에 원본! = myBitmap을 확인해야합니다.
Jeremyfa

1
@Jeremyfa 원본과 동일한 너비와 높이를 지정하면 원본 이미지 만 반환합니다. 이 경우 크기 조정은 문제가 있으므로 건너 뛰고 대신 원본 이미지를 반환하여 일부 프로세스를 절약 할 수 있습니다. 그것은 아무것도 ...하지만 "휴식"안
자바리

11

비트 맵이 메모리에로드되면 실제로 두 부분의 데이터로 만들어졌습니다. 첫 번째 부분은 비트 맵에 대한 정보를 포함하고 다른 부분은 비트 맵의 ​​픽셀에 대한 정보를 포함합니다 (바이트 배열로 구성됨). 첫 번째 부분은 Java 사용 메모리에 있고 두 번째 부분은 C ++ 사용 메모리에 있습니다. 서로의 메모리를 직접 사용할 수 있습니다. Bitmap.recycle ()은 C ++의 메모리를 해제하는 데 사용됩니다. 그렇게 만하면 GC는 Java의 일부를 수집하고 C의 메모리는 항상 사용됩니다.


+1은 흥미롭지 만 즉각적인 GC에서 메모리를 사용할 수없는 이유를 설명하는 아주 좋은 방법입니다.
Richard Le Mesurier 2013

8

Timmmm이 옳았습니다.

에 따르면 : http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html

또한 Android 3.0 (API 레벨 11) 이전에는 비트 맵의 ​​백업 데이터가 예측 가능한 방식으로 출시되지 않은 네이티브 메모리에 저장되어 잠재적으로 애플리케이션이 일시적으로 메모리 제한을 초과하고 충돌을 일으킬 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.