android, Bitmap 과 메모리에 대한 이야기, 끝판왕! |
안드로이드 메모리에 대한 이야기.
한 앱은 Dalvik Heap 과 External 두가지 영역이 존재한다.
Dalvik Heap 은 Java 에서 사용하는 메모리라고 보면 되고,
External 은 native 메모리라고 보면 된다.
Dalvik Heap 영역은 메모리가 꽉 차면 늘긴 하지만 그 공간이 줄지는 않는다.
반대로 External 영역은 유동적으로 그 공간이 늘었다 줄었다 한다.
( 특히 Ginger Bread 에서는 Java Object 관리를 잘못하면 심심하면 OOM 을 만날 수 있겠다. )
HoneyComb 이전에는 bitmap 은 native memory 에서 관리했으나,
HoneyComb 이후에는 bitmap 도 dalvik heap 으로 올라왔다.
프로세스당 메모리 = 애플리케이션 메모리 = 앱 메모리
단말기별로 다양하다.
보통 단말기의 화면 크기와 밀도가 커질수록 더 크다.
그만큼 화면을 채우려면 비트맵 이미지의 크기가 더 커져야 하기 떄문.
최초 Android 폰인 G1 의 경우 16MB 였다.
하지만 요즘은 32MB, 48MB, 96MB, 128MB 등으로 다양하다.
단말의 메모리 용량 확인하기.
프로세스 메모리 limit 보기
// MB 단위로 출력된다.
((ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass();
Dalvik Heap 영역 메모리 보기
// byte 단위
Runtime.getRuntime().maxMemory()
Runtime.getRuntime().totalMemory()
Runtime.getRuntime().freeMemory()
// 사용중인 메모리는
// totalMemory() - freeMemory();
cf) 필자의 단말은 Optimus G 인데 기본 Activity 띄우고 측정한 결과.
Total memory 는 96MB.
Dalvik Heap 은 약 19MB.
Native Heap 쪽 정보
Native 만 이용해서 프로그래밍 하는 경우가 아니면 꼭 필요하지 않지만 native 를 많이 이용하는 경우에는 사용할 수 있겠다.
MemoryInfo memInfo = new MemoryInfo();
am.getMemoryInfo( memInfo );
memInfo.totalMem
memInfo.threshold
memInfo.availMem
하지만 중요한 것은 Dalvik Heap 영역의 메모리이다.
Bitmap 은 recycle 을 불러주어야 하는가?
Bitmap 은 recycle 을 불러줄 필요가 있다.
사실 Bitmap 의 경우 finalize() 에서 메모리 해제 작업이 이루어지기는 하지만,
GC 에 따라서 ( 다시 말해 VM 에 따라 ) finalize() 의 호출이 언제 이루어질지 보장할 수도 없고,
운 없는 경우 아예 안 불릴수도 있다고 한다.
따라서 무조건 GC 를 믿고 있기보다는
메모리를 많이 차지하는 bitmap 일수록 유저가 recycle 을 이용해서
메모리를 관리해주는 것이 좋다.
공유하는 비트맵 해제에 대한 이야기.
RecyclingBitmapDrawable 클래스는 BitmapDrawable 클래스를 상속하며 reference count 를 가진다.
이미지 다운로더는 비트맵 대신 RecyclingBitmapDrawable 객체를 생성해서 반환한다.
RecyclingImageView 클래스는 ImageView 클래스를 상속하고, 다음 두 가지 메서드를 재정의한다.
setImageDrawable()
drawable 객체를 주입시킬 때 RecyclingBitmapDrawable 이라면 reference count 를 증가시킨다.
onDetachFromWindow()
window 에서 보이지 않게 되면 RecyclingBitmapDrawable 의 reference count 를 증가시키고, 이 때 0이면 recycle() 메서드를 호출한다.
cf) 이 RecyclingBitmapDrawable 과 RecyclingImageView 는 기본 Framework 에 들어있는 Component 는 아니나, Bitmap 관리에 필요하여 확장된 녀석들이다.
이미지 품질을 줄여서 메모리 줄이기.
비트맵 디코딩 옵션에 따라 메모리 사용량이 달라진다.
RGB_888 보다는 RGB_565 가 메모리를 아끼고,
RGBA 보다는 RGB 가 메모리를 아낀다.
JPG 같은 경우는 A 가 없으므로 RGB 를 사용하는 것이 메모리를 아낄 수 있다.
res 폴더의 경우 aapt 가 자동으로 이미지를 분석해서 이미지를 최적화시키기 때문에 decoding 에 큰 문제가 없으나, network 에서 불러온 녀석이나, asset 폴더에 있는 녀석들은 디코딩 옵션에 따라 메모리에 큰 영향력을 행사할 수도 있다.
Dalvik Heap 을 늘리자.
둘다 honey comb 이후부터 작동한다.
@Code
((ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE)).getLargeMemoryClass();
@xml
android:largeHeap="true"
apk 로 파일로 압축되는 파일 목록 줄이기.
android 는 앱을 실행할 때 .apk 파일에 든 모든 파일의 엔트리 정보를 메모리에 로딩한다.
res 나 asset 폴더에 그만큼 많은 resource 들이 있다면, 이 리스트들만 가지고도 메모리 부담이 될 수 있다.
만약 asset 부분에 파일이 많이 들어가게 된다면, ( 압축이 안 되므로 더 많은 메모리 차지.? )
DB 의 BLOC 칼럼을 만들어서 저장하는 것이 훨씬 좋다.
덧붙여 DB 에서 파일을 가져오는 것이 File 에 접근하는 것보다 더 빠를 수 있다.
최악의 상황에서는 프로세스를 분리하자.
Process 를 분리해서 처리하게 되면, 각각의 process 에서 사용가능한 메모리를 사용할 수 있지만,
그렇게 좋은 방법은 아니다.
항상 메모리 최적화를 최우선으로 고려하고, 그래도 안 되면 process 분리를 고려해야 한다.
Native Memory 를 사용하자.
여러가지 최적화를 해도 안 된다면 마지막으로 native heap 을 사용해볼 수 있다.
다만 native heap 을 사용하기 위해서는 JNI 와 C/C++ 코드를 사용해야 하기 때문에
유지보수도 어려워지고, 더 많은 인력이 쓰일 수 있다.
주로 메모리를 많이 쓰는 게임 앱 등에서만 사용한다.
'프로그래밍 놀이터 > 안드로이드, Java' 카테고리의 다른 글
[android] Share with facebook with ACTION_SEND intent, why pre-filled text does not work? (0) | 2014.02.05 |
---|---|
[android] how to make scrollview scroll to bottom programatically. (0) | 2014.01.27 |
[android] What's new in android Kitkat (0) | 2014.01.25 |
[android] ART ( android runtime ) 이란? (2017.08. updated) (0) | 2014.01.22 |
[android] minSdkVersion 에 대한 요즘 추세는 14. (0) | 2014.01.21 |
댓글