본문 바로가기

Android/Tips

Memory Leak 에 관하여

앱을 출시 하고나서 관리 하다보니 겪은 일이었습니다. 

앱이 버벅대고 느려진다는 이슈였습니다. 굉장히 크리티컬한 이슈였지요. 


원인을 찾아보니 OOM(OutOfMemory Exception) 에러였습니다. 허용 가능한 메모리가 꽉 차서 앱이 죽는 현상이 발생하는 것이었습니다. 이 원인을 해결하기위해 엄청나게 많은 시간을 쏟아부었습니다. 앱 내에 이미지를 보여주는 부분이 많았는데, 용량이 큰 이미지를 불러오거나 할 때 제대로 GC (Garbage Collect)가 되지않아서 메모리에 지속적으로 쌓이는 것이었습니다. 하지만 원인자체가 이미지 문제가 아니었습니다. 


원인은 객체의 참조로 인해 화면 종료시 GC가 제대로 되지 않으면서 계속적으로 Activity 객체들이 쌓이게되고 큰 이미지를 가지고 있는 Activity가 쌓이면서 결국 OOM 에러가 터진 것이었습니다. 


우선 메모리 릭 (Memory Leak)이 발생할 수 있는 부분은 매우 많습니다. 

 

1. WebView 

2. Handler

3. Image

4. Map 

5. View 의 동적생성 시 context 참조

6. 정적 변수 사용 시 

 

기타등등...


뭐가 딱 원인이다 하고 IDE 에서 알려주지는 않습니다. 개발자가 직접 하나하나 추적해 나가야 하는 방법 뿐입니다. 


MAT(Memory Analytics Tools)도 써보고 했지만, 그동안 경험을 바탕으로 알게된 방법을 알려 드리도록 하겠습니다. 


1. 앱을 빌드 후 IDE 상에서 Android Profiler 를 엽니다. 

2. Memory 부분에 보면 계속해서 메모리가 얼마씩 쓰고있는지 실시간으로 보이게 됩니다. 

3. 각 Activity(액티비티) 마다 같은 액티비티를 열었다 나왔다 하면서 memory 수치 여부를 확인하는데 이때 해당 액티비티를 여러번 들어갔다가 나와서 IDE 상에서 한번 'Force Garbage Collection' 을 실행하여 전과 후의 메모리 수치를 비교합니다. 

4. 반복 하다보면 특정 액티비티에서 메모리가 GC 되지 않고 계속 증가함을 알 수 있습니다. 

5. 액티비티를 찾았다면 내부적으로 참조를 하나하나 확인 해 가며 추적을 해야하는데, 바로 추측이 되어 처리할 수 있다면 다행이지만 도통 모르겠는 경우도 있습니다. 

6. 이럴 때는 메소드별로 하나하나 주석처리하며 아까 3,4 번을 반복하여 메모리의 비교를 통해 추적해 나가야합니다. 

7. 추가로 IDE 내부에서 'Force Garbage Collection' 옆의 버튼인 'Dump Java Heap' 버튼을 통해서 IDE 내부에서 각각의 인스턴스와 메모리 보유율을 알 수 있는데 여기서도 activity별로 분류 정렬하여 어떤 액티비티가 몇개의 instance를 가지고 있는지 추적이 가능합니다. 



* 이래도 모르겠다 하시면 Memory Heap 파일을 Dump떠서 실제 MAT 를 이용해서 하나하나 인스턴스 갯수를 찾아가며 하는 방법이 있습니다.



이렇게 하다보면 어느부분에서 참조로 인해 GC처리가 안되어 Leak이 일어나는지 추적이 가능합니다. 


대부분의 경우 이런 케이스로 해결이 가능하였습니다. 



이 방법 외의 경우 이미지 자체의 크기로 인해 OOM이 터질경우에는, 


메모리의 공간 차지 없이 이미지의 크기를 불러온 후, 해당 이미지를 허용 가능한 메모리 이내로 축소 처리 하여  이미지를 위젯에 띠우도록 하는 방법을 쓰면 됩니다. 

(참고 - https://developer.android.com/topic/performance/graphics/load-bitmap.html)


추천드리지는 않지만, Glide를 쓴다면 최후의 방법으로 Glide를 쓰면서 메모리에 캐싱된 이미지들을 gc처리 함으로써 메모리 확보도 가능은 합니다. 하지만 이 방법은 정말 비추천입니다. 매번 이미지를 띠워야할 때마다 url 또는 내부 경로로부터 매번 새롭게 가져와야 하는 로드가 생기기 때문에 앱이 버벅이거나 무리가 갈 수 있습니다. 


따라서 위의 1~6번의 방법으로 최대한 메모리의 누수를 추적하시는게 제일 좋은 방법인 것 같습니다. 


더 좋은 방법이 있다면 댓글 또는 메일로 알려주시면 보완후 업데이트 하도록 하겠습니다.