[Android] Glide에서 비트맵 이미지가 GC되는 과정
개요
위의 공식 문서에서 나와있는 바와 같이 기본적으로 Glide로 비트맵을 관리하는 걸 추천하고 있다.
이를 관리해줘야 하는 이유는 다음과 같다.
앱에서 대량의 비트맵 데이터를 표시하면 OutOfMemoryError 오류가 발생할 수 있습니다.
OutOfMemory 오류를 방지하기 위하여 안드로이드에서는 recycle() 기능을 제공하는데, 이 메소드를 실행하면 비트맵에 사용한 메모리를 회수할 수 있다. 즉, 이 메소드를 호출함으로써 해당 비트맵은 GC의 대상이 된다. 당연히 해당 비트맵을 더이상 사용하지 않을 거라고 확정된 시점에 호출해야한다.
Glide는 비트맵의 메모리를 어떻게 관리하고 있는가?
메모리 캐시 vs 디스크 캐시 의 내용에 따르면 비트맵 캐싱은 LruCache를 사용하는 대표적인 예
다. 여기서 힌트를 얻어서 Glide를 적용하면서 설정했던 BitmapPool 사이즈 디폴트값을 보자. 관련 코드는 다음과 같다.
1 | // 비트맵 풀: The default size is based on the screen size and density of the device |
BitmapPool 사이즈는 단말의 스크린사이즈와 density 값에 따라 달라진다고 나와있다.
Glide에서 비트맵의 라이프사이클 링크
Glide에서 비트맵을 관리하는 데에 있어 일반적인 생명주기는 다음과 같다.
InputStream -> Bitmap -> View -> Memory Cache -> Bitmap Pool -> Recycle
해당 링크 해석본
비트맵은 메모리 캐시 또는 BitmapPool에서 View(또는 target) 및 Loop로 이동할 수도 있습니다. 디코딩 파이프 라인 (예 : 변환을 통해) 중에 리소스를 수동으로 재활용하는 경우 비트맵이 표시되지 않고 recycled state가 될 수도 있습니다. 그렇지 않으면 비트맵이 크기 제약으로 인해 제거될 때 메모리 캐시에서 BitmapPool로, BitmapPool에서 recycled state로 이동합니다.
“Cannot obtain size for recycled Bitmap” 오류는 Recycle state에 도달한 비트맵을 그리려고 할 때 발생합니다. 결코 발생해서는 안되지만 다음과 같은 몇 가지 시나리오에서 발생할 수 있습니다.
변환 중에 디코딩 프로세스 중에 비트맵을 수동으로 recycle할 경우
이 원인은 일반적이지 않은 브랜치에서 커스텀 변환을 하지 않는 한 이런 상황을 꽤 자주 볼 수 있습니다.
디코딩 프로세스 중, 변환 중에 두 번 이상 Pool에 비트맵을 반환한 경우
이 경우 문제의 원인을 파악하기 쉽습니다. 비트맵이 Pool에서 제거되지 않고 Pool에 여러 번 추가되면 다른 이미지가 동시에 표시되어, 두 개의 이미지 중 하나는 올바르게 표시되고 다른 하나는 잘못 표시 될 수 있습니다. 게다가 다른 뷰에서 참조하는 동안 동시에 recycle 될 수도 있습니다.
onLoadCleared가 호출된 후에도 계속 리소스를 참조하거나, 또는 해당 Target이 지워진 후 Target에 로드된 리소스를 참조한 경우
커스텀 target을 사용하는 경우 발생할 수 있습니다.
안타깝게도 비트맵을 추적하기 위해 수동 참조 계산을 수행해야하므로 이러한 종류의 버그를 추적하는 것이 매우 어려울 수 있습니다.
BitmapPool의 크기를 크게 줄이거나 BitmapPoolAdapter를 사용하여 충돌이 더 자주 발생하는지 확인하십시오. 메모리 캐시의 크기를 줄일 수도 있습니다. 두 경우 모두 파이프 라인의 길이를 줄입니다. 이는 Bitmap이 Recycled state에 더 빨리 도달하여 오류가 더 자주 발생할 수 있음을 의미합니다. 또한 비트맵 렌더링 오류, 기록 된 GL 경고 또는 다른 이미지 대신 잘못된 이미지가 나타나는지 주시하십시오. 이 모든 것은 버그를 재현한 신호입니다.
결론
따라서 Glide는 변환된 Bitmap을 내부적으로 recycle하기 때문에 imageView.setRecycler()
하지 않아도 된다.