일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- jobschduler
- Library
- epmty
- Background
- PHP
- jobdispatcher
- schedule
- Job
- workmanager
- Service
- alarmanager
- shceduler
- firebase
- livedatam
- 검사
- 빈
- Android
- Today
- Total
에몽이
안드룅드 메모리 누수 이슈 본문
Android Memory Leak이 발생되는 원인과 해결 방안에 대하여 알아본다. Integrated Development Environment(이하 IDE)은 Eclipse를 기반으로 설명한다.
1. Android Memory Leak
이 장에서는 버전에 따른 Android 메모리 체계를 살펴보고 Bitmap 사용 시 왜 Out Of Memory(이하 OOM)가 자주 발생되는지 알아보도록 하겠다.
1.1 Android Memory 체계
Android 메모리 모델은 Honeycomb을 기준으로 Honeycomb 미만과 이상의 메모리 모델로 나눈다.
1.1.1 Honeycomb 미만 Memory 체계
Honeycomb 미만에서 Android 메모리는 Java Heap 영역과 External Heap 영역으로 나눈다.
Dalvik Heap에는 Java 객체가 저장되며, External Heap(Native Heap의 일종으로 프로세스당 사용 가능한 크기가 정해져 있는 점이 다르다)에는 Bitmap Pixel data가 저장된다.
Dalvik Heap은 Footprint[4]가 증가만 되고 감소하지 않는다. 이는 자칫 OOM을 발생시킬 수 있는데 자세한 설명은 줄어들지 않는 Footprint 이슈를 참고하기 바란다.
Davik Heap + External Heap이 프로세스당 메모리 한계를 초과하면 OOM이 발생한다.
그림 1‑1 Honeycomb 미만 메모리 모델
(http://helloworld.naver.com/helloworld/539525)
1.1.2 Honeycomb 이상 Memory 체계
Honeycomb 버전부터 external heap 영역이 사라졌으며, Dalvik Heap Footprint는 상황에 따라 증가하고 감소하도록 개선되었다.
아래 그림은 Honeycomb 이상에서 메모리 모델을 표현한 것이다.
그림 1‑2 Honeycomb 이상 메모리 모델
1.2 Honeycomb 미만 Memory 이슈
Gingerbread 이하에서는 OOM을 발생시키는 몇 가지 주요 이슈가 있다.
• 줄어들지 않는 Footprint 이슈
• Bitmap 객체의 메모리 반환 이슈
Dalvik VM은 동작에 필요한 만큼만 프로세스에 Heap을 할당한다. 그리고 프로세스에 할당된 메모리보다 많은 메모리가 필요한 경우, 프로세스에 할당 가능한 Max Heap Size 내에서 필요한 만큼 Heap Size를 증가시켜주며 Max Heap Size를 초과하는 경우 OOM이 발생된다.
문제는 한 번 증가된 Dalvik Footprint의 크기는 줄어들지 않는다는 것이다. 아래 그림을 보면 Java에서 사용 중인 메모리가 증가할 때마다 Footprint는 지속적으로 증가하고 감소하지 않는 것을 볼 수 있다. 이렇게 Footprint가 증가하기만 하면 Java 객체가 사용 가능한 메모리 공간은 여유가 있어도 External Heap크기가 증가될 때OOM이 발생될 수 있다.
그림 1‑3 Davik Heap Snapshot
(http://www.kandroid.org/board/board.php?board=conference&command=body&no=88)
그래서 Honeycomb 미만 버전에서 OOM이슈 방지를 위해서 Footprint의 크기가 지속적으로 증가되지 않도록 관리하는 것이 중요하다.
1.2.2 Bitmap 메모리 반환 이슈
Honeycomb 미만에선 Bitmap Object는 dalvik heap 영역에 저장되고, 실제 pixel data는 Native heap(external memory) 영역에 저장된다. Bitmap object는 pixel data의 메모리 주소를 저장하고 이미지 정보를 관리할 뿐이다.
그림 1‑4 Gingerbread 이하 버전의 Bitmap 객체
Java에서 객체는 일반적으로 객체 참조가 더 이상 없으면 GC에 의하여 메모리에서 해제된다. 그러나 bitmap pixel data는 native heap 영역에 저장되어 GC에 의하여 자동으로 메모리 해제가 되지 않는다. 그래서 Gingerbread 이하에서는 아래 소스 코드처럼 Finalizer Guardian 기법을 이용하여 Bitmap Pixel Data를 제거하도록 구현되었다.
아래 코드는 Bitmap.java 소스 코드 일부이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | @SuppressWarnings ({“UnusedDeclaration”}) // called from JNI Bitmap( int nativeBitmap, byte [] buffer, int width, int height, int density, boolean isMutable, boolean isPremultiplied, byte [] ninePatchChunk, int [] layoutBounds) { // 생략 // we delete this in our finalizer mNativeBitmap = nativeBitmpa; mFinalizer = new BitmapFinalizer(nativeBitmap); // 생략 } private static class BitmapFinalizer { private final int mNativeBitmap; BitmapFinalizer( int nativeBitmap) { mNativeBitmap = nativeBitmap; } @Override public void finalize() { try { super .finalize(); } chtch (Throwable t) { // Ignore } finally { nativeDestructor(mNativeBitmap); } } } </span></span> |
그러나 해당 코드는 종종 Native Heap 영역에 있는 메모리를 반환하지 못해 OOM을 발생시키는데 그 원인은 finalize 메서드에서 bitmap pixel data를 메모리에서 반환하도록 처리하였기 때문이다.
finalize 메서드를 사용하는 경우 finalization queue에 queuing되고, finalizer에 의해 순차적으로 finalize 메서드가 호출된다. 이런 이유로 finalize 메서드가 호출되는 시점 및 pixel data가 메모리에서 해제되는 시점을 알 수 없으며, 이로 인해 OOM이 발생될 수 있다.
참고
finalize가 호출되는 방식을 이해하려면 GC에 대한 내용을 먼저 살펴본다.
http://helloworld.naver.com/helloworld/329631
그림 1‑5 Honeycomb 이상 버전의 Bitmap 객체
(http://static.googleusercontent.com/media/www.google.com/ko//events/io/2011/static/presofiles/memory_management_for_android_apps.pdf)
1.3 Bitmap에서 자주 OOM이 발생하는 이유
Bitmap 사용 시 OOM이 자주 발생하는 이유는 다음과 같다.
• Android 앱 전체 메모리 중에서 Bitmap이 차지하는 비율은 휴대폰은 50%, 태블릿과 같은 큰 화면에서는 70%를 차지한다[1].
• Android에서 사용 가능한 Heap Size는 단말기 별로 다르긴 하지만 16MB ~ 48MB로 제한적이다(2011년 기준).
Honeycomb 미만에서 Heap Size가 크지 않은 이유는 초기 Android가 저가 시장을 타겟으로 설계되었기 때문에 큰 용량의 메모리를 사용할 수 없었다. 그러다 보니 Process당 사용할 수 있는 Heap Size가 작은 것이다.
그러나 테블릿 시장을 타겟으로 한 Honeycomb(3.0)이 나오면서 Process당 Heap Size가 늘어났으며, 게임처럼 메모리를 많이 사용하는 앱들을 위해 android:largeHeap=”true” 옵션을 제공하여 2 ~ 4배 더 많은 Heap을 할당 받을 수 있게 되었다.
주의
largeHeap 옵션을 사용하면 그만큼 가비지 컬렉션(Garbage Collection 이하 GC) 시간을 더 소비한다는 의미이며, 다른 LMK(Low Memory Killer)가 좀 더 빠르게 발생되어 앱들을 종료시킬 수 있습니다[2].
2. Memory Leak 확인 방법.
이 장에서는 Memory Leak을 확인하는 2가지 방법을 소개한다.
2.1 Android Development Tools 이용 방법
이 방법은 Android Development Tools(이하 ADT)에서 제공하는 기본 기능으로 별도의 Plug-In 설치 없이 Memory Leak이 발생되는지 체크해 볼 수 있는 간단한 방법이다.
아래는 ADT를 이용하여 테스트하는 방법이다.
1. 사용 방법은 DDMS 화면을 연 후 체크하고자 하는 프로세스를 선택하여 Update Heap 버튼을 클릭한다.
2. 화면 오른쪽에서 Heap 탭을 선택하여 Cause GC 버튼을 클릭한다.
3. 그러면 아래 그림과 같이 동작 중인 프로세스에 대한 현재 메모리 정보가 나타난다.
4. 중간 중간에 Cause GC 버튼을 클릭하여 해당 프로세스에게 garbage collection을 요청한다.
5. 이때 메모리가 해제되거나 증가되는 상황을 통해 메모리 누수 시점을 추측할 수 있다. 중요하게 볼 부분은 Allocated Memory로 실제 사용 중인 메모리 양을 뜻한다.
6. Heap Size는 위에서 설명한 대로 Gingerbread 이하 버전에서는 증가만하고, Honeycomb 버전부터는 현재 상황에 맞게 증가하고 감소한다.
7. Gingerbread에서 동작하도록 개발한다면 Heap Size는 최대한 늘어나지 않게 하는 것이 좋다.
그림 2‑1 Memory Leak 테스트를 위한 프로세스 선택
그림 2‑2 GC 강제 발생
2.2 Memory Leak 발생 지역 축소
복잡한 프로그램에서 Memory Leak을 찾기는 어렵다. 이때는 화면 단위로 나누어서 찾아보면 발생 지역이 축소되어 원인을 찾는 데 도움이 된다.
예를 들어 Activity A, B가 있을 때 B Activity에서 Memory Leak이 있는지 확인하고 싶을 경우 아래와 같이 진행한다.
1. A Activity 실행 후 Cause GC버튼을 클릭하여 현재 상태를 확인한다.
2. B Activity로 이동 후 다시 A Activity로 이동한다.
3. 1, 2번을 반복 수행한다.
4. 이때 A Activity에서 Cause GC을 클릭하여 강제 GC를 발생시켰을 때 Allocated에 메모리가 줄어들지 않고 점점 늘어난다면 문제가 있는 것으로 볼 수 있다.
그림 2‑3 A Activity에서 강제 GC 후 메모리 상태
그림 2‑4 B Activity에서 강제 GC 후 메모리 상태
그림 2‑5 A <-> B 반복 후 A Activity에서 강제 GC 이후 메모리 상태
2.3 Eclipse MAT Plug-In을 이용한 분석 방법.
Android Development Tools(이하 ADT)에서는 자세한 Heap 정보를 제공하지 않으므로 보다 자세한 Heap 정보는 Memory Analyzer Tool(이하 MAT)을 이용해야 한다. MAT는 “http://www.eclipse.org/mat/”에서 내려받을 수 있다.
MAT는 Eclipse Plug-In으로 Java Heap Memory 분석 도구다. 빠르고 많은 기능을 제공하며, 이것을 이용하여 Memory Leak을 발견하거나 분석을 통해 메모리 사용을 줄이는 데 도움을 준다.
2.3.1 DDMA를 통해 Heap Dump 가져오기
Memory 상태를 보고 싶은 순간에 DDMS 화면에서 Dump HPROF 버튼을 클릭한다.
그림 2‑6 Heap Dump 가져오기 1
아래 그림과 같이 Dump file을 만드는 것을 볼 수 있다. heap dump가 끝나면 현재 메모리 상태를 분석할 수 있다.
그림 2‑7 Heap Dump 가져오기 2
2.3.2 특정 동작 상태에 대한 Heap Dump 가져오기
특정 동작 시점에 대한 Heap Dump 를 가져오기 위해서는 코드를 이용하여 자동으로 Heap Dump 를 가져오도록 만들어야 한다. Heap Dump 를 가져오고 싶은 시점에 “Debug.dumpHprofData(String fileName)” 코드를 추가한다.
heap dump 파일이 생성되면 MAT 에서 분석 가능한 파일로 변경시켜야 하는데 명령어는 다음과 같다.
hprof-conv [변환 대상 파일 경로] [저장 파일 경로]
* hprof-conv 파일은 adb 파일이 있는 경로에 존재합니다.
그림 2‑8 hprof-conv 가져오기
변환된 heap dump 파일을 MAT에서 분석하기 위해선 Memory Analysis 화면으로 이동하여 파일을 불러 오면 된다.
그림 2-9 dump 파일 로드
3. Memory Leak 피하는 방법
Android 앱 개발 시 여러 가지 문제로 Memory Leak이 발생한다. 이 장에서는 Memory Leak 발생을 최소화하기 위한 몇 가지 방법을 소개한다.
3.1 Bitmap 관리
안드로이드에서 메모리를 가장 많이 사용하는 것은 Bitmap이며 Bitmap만 잘 관리해도 많은 OOM 발생을 방지할 수 있다. 아래 몇 가지 Bitmap을 관리하는 방법을 소개한다.
3.1.1 명시적으로 메모리 해제
Honeycomb 미만 버전에서는 Bitmap Pixel Data가 Native 영역에서 관리되었고 Bitmap 객체가 모든 참조가 끊어져 GC가 된다 하더라도 finalize 이슈와 관련해서OOM이 발생될 수 있다. 그래서 Google에서는 Gingerbread 이하 버전에서 Bitmap을 사용할 때는 Bitmap.recycle()을 명시적으로 호출하도록 가이드하고 있다[10].
Bitmap.recycle()을 이용하면 Bitmap pixel data가 메모리에서 바로 해제된다. 그러나 사용 중인 Bitmap을 recycle()하면 문제가 생길 수 있으므로 주의해서 사용해야 한다.
3.1.2 효율적인 이미지 로드
768 x 1024픽셀 크기의 이미지는 약 3MB의 메모리를 차지한다. Dalvik Heap 크기가 32MB일 경우 약 10개의 이미지를 로드하면 더 이상 이미지를 로드할 수 없다. 화면을 그리고 앱을 실행하는 데 기본적으로 차지하는 공간이 있어 실제 로드할 수 있는 이미지는 몇 개 되지 않는다.
그러나 ImageView의 크기가 100 x 100픽셀에 이미지를 보여줄 경우 40KB만 있으면 되는데 3MB나 소비하고 있어 낭비되는 메모리가 2.96MB나 된다. 메모리 낭비를 최소화하기 위해서는 Image Sampling을 이용하여 이미지를 로드한다.
아래는 Android Developer Site에 나와 있는 Image Sampling코드이다[11].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | public static int calculateInSampleSize( BitmapFactory.Options options, int reqWidth, int reqHeight) { // Raw height and width of image final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1 ; if (height > reqHeight || width > reqWidth) { final int halfHeight = height / 2 ; final int halfWidth = width / 2 ; // Calculate the largest inSampleSize value that is a power of 2 and keeps both // height and width larger than the requested height and width. while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) { inSampleSize *= 2 ; } } return inSampleSize; } public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) { // First decode with inJustDecodeBounds=true to check dimensions final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true ; BitmapFactory.decodeResource(res, resId, options); // Calculate inSampleSize options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); // Decode bitmap with inSampleSize set options.inJustDecodeBounds = false ; return BitmapFactory.decodeResource(res, resId, options); } </span></span> |
3.1.3 효율적인 이미지 변경
이미지 작업을 하다보면 여러 가지 변형을 해야 하는 경우가 있다. 예를 들어 이미지 축소, 확대 후 회전과 같은 작업을 해야 하는 경우가 있다. 이때 이미지 변형 작업을 순차적으로 하는 경우 메모리도 많이 사용하고 속도도 느리다.
예제. 이미지 축소 후 회전시키는 코드
1 2 3 4 5 6 7 8 9 10 11 | Bitmap resizedBitmap = Bitmap.createScaledBitmap(bitmap, width, height, false ); Matrix matrix = new Matrix(); matrix.setRotate( 90 , ( float ) bitmap.getWidth() / 2 , ( float ) bitmap.getHeight() / 2 ); Bitmap rotatedBitmap = Bitmap.createBitmap(resizedBitmap, 0 , 0 , resizedBitmap.getWidth(), resizedBitmap.getHeight(), matrix, true ); resizedBitmap.recycle(); // Gingerbread 버전을 대응한다면 바로 메모리에서 해제 시켜줘야 한다. </span></span> |
resizedBitmap은 이미지 rotate 이후에는 더 이상 불필요하기 때문에 resizedBitmap.recycle()을 사용하여 메모리를 해제한 것이다.
물론 일부러 이렇게 하는 경우는 없겠지만 이전에 만들어 놓은 rotate, scale 기능을 한 번씩 호출할 경우 결국 위 코드와 같아지는 것이다.
이때는 Matrix를 이용해서 이미지 변형 작업을 모아서 하는 것이 속도도 빠르고 메모리도 적게 사용한다.
예제. Matrix를 이용한 Bitmap 처리
1 2 3 4 5 6 7 8 | Matrix matrix = new Matrix(); matrix.setScale(width, height); matrix.setRotate( 90 , ( float ) bitmap.getWidth() / 2 , ( float ) bitmap.getHeight() / 2 ); Bitmap transformedBitmap = Bitmap.createBitmap(bitmap, 0 , 0 , bitmap.getWidth(), bitmap.getHeight(), matrix, true ); </span></span> |
Android는 앱 실행 시 “res/”에 있는 리소스들을 메모리로 로드한다. 그래서 리소스에 있는 이미지를 불러와 사용하는 경우 overload가 크지 않은 것이다.
물론 Bitmap의 경우 APK 파일을 만들 때 이미지 최적화 작업을 하는데 이때 Bitmap.Config.RGB565 등의 이미지로 적절하게 변환되면서 메모리를 많이 사용하지 않도록 변환된다.
그렇다고 해도 사용되지 않는 Bitmap 이미지가 많은 경우 이미지 특성상 메모리가 많이 사용되므로 사용되지 않는 리소스는 정리를 하는 것이 좋다.
아래 그림은 사용되지 않는 리소스를 제거하기 전, 후의 메모리 상태이다.
그림 3‑1 사용되지 않는 리소스 제거 전
그림 3‑2 사용되지 않는 리소스 제거 후
그러나 앱 유지 보수를 오래하다 보면 지우지 못한 리소스가 점점 쌓이게 되고 어떤 리소스가 사용되지 않는지 찾기가 어렵다. 이런 경우 “android unused resource”[12] 프로그램을 이용하여 사용되지 않는 리소스 목록을 얻을 수 있다.
Android unused resource는 Open Source로 만들어진 프로젝트로
https://code.google.com/p/android-unused-resources/ 에서 받을 수 있다.
그림 3‑3 android unused resource 실행 결과
“android unused resource”는 사용되지 않는 리소스 목록이 많을 경우 리소스 제거 역시 쉽지 않아 자동으로 리소스를 삭제하는 기능을 추가해 보았다.
소스는 https://github.com/lsit81/android-unused-resources에서 받을 수 있다.
주의
리소스 자동 삭제 기능을 사용할 경우 원본을 백업한 후 사용해야 한다.
리소스 이름을 동적으로 사용할 경우 사용되지 않는 리소스로 판단되기 때문이다.
3.3 Activity Context 생명 주기 관리
해당 이슈는 잘 알려진 이슈로[8] Activity Context가 전역 변수에 계속 쌓이거나 순환 참조되는 경우 Activity Context가 GC되지 않고 계속 메모리에 쌓이게 된다.
Activity Context는 무거운 객체이므로 메모리에서 해제되지 않는 경우는 쉽게 Memory Leak 이 발생될 수 있다.
예제. Activity가 메모리에서 해지되지 않는 경우
1 2 3 4 5 | @Override protected void onResume() { GlobalStatus.addTopApplicationChangeListener( this ); } </span></span> |
Context 관련 leak을 피하기 위해서는 다음과 같이 작업한다.
• Activity Context 관련하여 오래 유지되는 reference를 유지하지 않는다.
• Activity Context의 Reference 생명 주기는 반드시 Activity 생명 주기와 동일해야 한다.
• Activity Context 대신 Application Context 사용을 고려한다.
• 생명 주기가 관리되지 않는 inner class에서 context 관련된 reference 관리를 피한다.
• static inner class에서 Activity를 Week reference로 참조한다.
3.4 finalize 메소드 사용 주의
일반적으로 finalize 메서드에서 메모리 반환 작업을 하는 경우는 Java Native Interface(이하 JNI)를 이용하여 메모리 할당을 받은 경우이다. finalize는 신속하게 실행된다는 보장이 없으며, 수행 속도 및 수행 타이밍은 GC 알고리즘에 따라 다르다. 그러므로 finalize 내부에 메모리 해제 코드를 넣을 경우 메모리 회수가 지연되어 OOM이 발생될 수 있다.
finalize()에서 Native Memory를 해제하는 코드를 넣는 것은 좋은 방법이 아니며 open(), close() 함수처럼 명시적으로 호출해서 사용한다. 그래서 Finalize는 개발자의 실수를 방지하기 위한 안전 망 역할로 사용해야 한다[9].
3.5 Footprint 증가 주의
Honeycomb 이상 버전에서 동작하도록 개발한다면 문제되지 않지만 Gingerbread를 포함하여 동작하도록 개발한다면 Footprint의 증가를 주의해야 한다.
줄어들지 않는 Footprint 이슈에서 설명했듯이 Honeycomb 미만 버전에서는 Footprint가 줄어들지 않기 때문에 생각지도 못한 OOM이 발생할 수 있다.
3.6 Native Heap 사용
여러 가지 방법들을 사용해 보았으나 그래도 메모리가 부족하다면 native heap 사용을 고려해 볼 수 있다. native heap은 JNI 기술을 이용하여 사용할 수 있으며 사용 가능한 메모리 크기는 시스템의 메모리 크기까지 사용할 수 있다.
JNI 사용법은 The Java™ Native Interface Programmer’s Guide and Specification (http://www.worldcolleges.info/sites/default/files/jni.pdf)를 참고한다.
참고로 안드로이드에서 JNI를 사용할 수 있도록 Native Development Kit (이하 NDK) 툴을 제공한다[14].
3.7 프로세스 분리
Android에서는 앱을 여러 개의 프로세스로 동작시킬 수 있도록 manifest.xml에 android:process 옵션을 제공하고 있다[13].
이렇게 프로세스를 분리하면 프로세스 별로 별도의 메모리를 사용하기 때문에 메모리 면에서는 여유가 생기나 프로세스간 메모리가 공유되지 않고, 각 프로세스 별로 리소스가 할당되어 메모리 효율성은 Native Heap을 이용하는 것보다는 떨어진다.
참고문헌
[1] Patrick Dubroy, Memory management for Android Apps, 2011. 05. 12, <http://www.youtube.com/watch?v=_CruQY55HOk&feature=youtu.be>
[2] Patrick Dubroy, Memory management for Android Apps, 2011. 05. 12, <http://static.googleusercontent.com/media/www.google.com/ko//events/io/2011/static/
presofiles/memory_management_for_android_apps.pdf>
[3] 박성현, Android 앱 메모리 최적화, 2013.11.05, Line+, <http://helloworld.naver.com/helloworld/539525>
[4] WIKIPEDIA, <http://en.wikipedia.org/wiki/Memory_footprint>
[5] 이경민, 양정수, Kandroid conference memory and performance, 2013.03.30, <http://www.kandroid.org/board/board.php?board=conference&command=body&no=88>
[6] 돼지와왕돼지 놀이터 블로그, finalizer 사용을 피하자, 2012.02.13, <http://aroundck.tistory.com/174>
[7] 박세훈, Java Reference와 GC, 2013. 04. 02, NHN Business Platform, <http://helloworld.naver.com/helloworld/329631>
[8] Avoiding memory leaks, 2009.01.19, Android Developers Blog,
<http://android-developers.blogspot.kr/2009/01/avoiding-memory-leaks.html>
[9] Effective Java Joshua Bloch, 『대웅 출판사』, (심재철 옮김), 2009 – finalize의 사용을 피하자
[10] Managing Bitmap Memory, Android Developer Site,
<https://developer.android.com/training/displaying-bitmaps/manage-memory.html#recycle>
[11] Loading Large Bitmaps Efficiently, Android Developer Site
<https://developer.android.com/training/displaying-bitmaps/load-bitmap.html>
[12] Open Source, <https://code.google.com/p/android-unused-resources/>
[13] Processe and Threads, Android Developer Site
<http://developer.android.com/guide/components/processes-and-threads.html>
[14] Android NDK, Android Developer Site
<http://developer.android.com/tools/sdk/ndk/index.html>
'android' 카테고리의 다른 글
안드로이드 ndk 기존의 것에 추가하기 (1) | 2017.02.08 |
---|---|
autocomplete, filter 예제 코드 및 주요 오류 (0) | 2017.02.07 |
나인패치 이미지 만들기 싸이트 (0) | 2017.01.16 |
서비스 예제 (0) | 2017.01.15 |
글라이드 bitmap으로 저장 (0) | 2017.01.15 |