본문 바로가기

안드로이드 Android

안드로이드 개발 (5) - 메모리 누수

복습한 것을 정리합니다.

 

가비지 콜렉터 (GC)란?

모든 어플리케이션은 작업을 하는데 필요한 메모리가 필요한데 가비지 콜렉터가 이에 대한 메모리를 확보를 해줍니다. Android 의 경우 런타임에서 메모리가 부족한 경우에 가비지 콜렉터를 트리거해서 어플리케이션을 원활히 동작할 메모리를 다시 확보를 해줍니다.

 

가비지 콜렉터의 수집은 3단계로 진행이 됩니다.

1) 메모리에 있는 모든 객체 참조를 나열 해서 참조가 있는 활성객체를 표시 

2) 1)에서 표시가 되지 않는 객체들을 메모리에서 제거 

3) 살아있는 객체를 재 정렬

 

가비지 콜렉터는 이런식으로 수집해서 메모리를 확보해줍니다.

메모리 누수란? 

어플리케이션에서 사용하지 않는 객체가 사용중인 어떠한 객체를 참조중이라서 사용되지 않는 객체를 

GC가 결국 사용되지 않는 객체의 할당된 메모리를 되찾아올 수 없는 현상입니다. 

 

메모리 누수가 지속 되면 무슨일이 일어나는가?

1) 앱 버벅거림

위에서 가비지 콜렉터는 Android 런타임에서 메모리가 부족할 때 작동된다고 언급을 하였습니다. 즉 회수 할수 없는 메모리가 많으면 많을 수록 Android 런타임에서 메모리가 자주 부족해 가비지 콜렉터를 많이 호출하게 된다는 뜻입니다. 이는 결국 실사용자가 느끼는 앱 버벅거림으로 이어집니다.

 

왜냐하면 가비지콜렉터가 발생하는순간 안드로이드의 UI렌더링 이나 이벤트처리를 중지시킵니다.

안드로이드는 기본적으로 16ms로 화면을 그리고 있습니다. 즉, Android 런타임에 메모리가 부족하면 가비지콜렉터가 자주 호출되서 UI 렌더링 그리는것을 연속적으로 멈출것이고 이 16ms이 유지가 되지 못합니다.

 

그렇게 사용자는 앱 버벅거림을 느끼게 됩니다. 

그러면 앱 사용자는 바로 GooglePlay 리뷰에 한마디를 남기겠죠.

"렉이 너무 심해요!!"

메모리 누수는 그렇게 앱 운영 기업에게도 큰 타격을 줍니다.

 

2) 앱 중단

안드로이드는 앱의 응답을 액티비티 매니저윈도우 매니저 시스템 서비스로 항상 모니터링되고 있습니다. 

하지만 5초 이내에 입력이벤트가 없거나 BroradCastReceiver가 10초 내에 실행을 완료하지 않을때

ANR 다이얼로그를 앱에 띄웁니다. 

 

그렇게 Google Play 리뷰에 한마디가 더 추가가 될겁니다

"앱이 자꾸 멈춘다는 표시가 떠요!!"

 

그리고 가비지 콜렉터의 잦은 호출뿐만 아니라 메모리 누수로 인해서 메모리 부족 현상이 일어나기도 합니다.

그러면 어플리케이션은 안드로이드 시스템에게 요구합니다.

 

"메모리좀 더줘요!!!"

하지만 안드로이드 OS의 대답은 이러합니다. 

"Noob.. 다른 어플도 돌려야돼 똑같이 너도 나눠 받았는데 뭐가 불만이야? 안돼"

 

어플리케이션은 결국 메모리 부족으로 허덕이다.

Out of Memory 라는 유언을 남기면서 결국 앱이 강제종료됩니다.

 

 Google Play 리뷰에 한마디 추가 됩니다.

"앱이 강제 종료되요!!"

위 2가지만 봐도 메모리 누수가 얼마나 무서운 녀석인지 깨닫게 됩니다.

 

메모리 누수 디버깅 방법??

메모리 누수는 결론적으로 잡기가 너무 어렵지만.. 안드로이드에서 

https://developer.android.com/studio/profile/memory-profiler?hl=ko 

 

메모리 프로파일러를 사용하여 앱의 메모리 사용량 검사  |  Android 개발자  |  Android Developers

끊김 현상, 멈춤, 심지어 비정상 종료를 일으킬 수 있는 메모리 누수 및 메모리 변동을 식별하는 데 도움이 되는 Android 프로파일러의 메모리 프로파일러 구성요소를 알아보세요.

developer.android.com

메모리 프로파일러를 지원 해줍니다. 

 

혹은 스퀘어사에서 만든 

https://square.github.io/leakcanary/

 

LeakCanary

🤔 Documentation issue? Report or edit LeakCanary 🐤 LeakCanary is a memory leak detection library for Android. LeakCanary’s knowledge of the internals of the Android Framework gives it a unique ability to narrow down the cause of each leak, helping

square.github.io

LeackCanary를 사용하는것도 좋습니다.

 

 

그럼 Android에서 메모리 누수의 원인은 ??

 

과거 안드로이드에서 메모리 누수의 여러 원인이 있었습니다.

 

1. 액티비티에서 inner Class 를 사용

https://fsd-jinss.tistory.com/144

 

4. memory leak 회피방법: 익명클래스를 주의하라

앞선 포스팅 (3. memory leak 회피방법: Inner Class Reference를 주의하라) 과 원리는 동일하다. Class에서 익명 class를 만들게되면 익명클래스의 instance는 outer class의 instance에 대해서 reference를 가지..

fsd-jinss.tistory.com

2.  Static 뷰 객체를 액티비티에서 사용 

static TextView  tv = new TextView(this) 의 경우,

 

3. handler를 액티비티가 종료된 후에도 사용 

https://medium.com/@joongwon/android-memory-leak-%EC%82%AC%EB%A1%80-6565b817a8fe

 

[Android] Android Memory Leak 사례

Android를 개발하다 보면 무의식중에 Memory Leak을 유발하는 코드를 작성하게 될 가능성이 있다.

medium.com

4. 싱글톤 객체에서 액티비티 Context 참조

(onDestory에서 해당 객체를 null를 하거나 가장 좋은건 application Context를 사용하는것이다. )

등등...

많은 주된 원인이 있습니다. 

 

 

2021년 버전으로 구체적인  안드로이드의 메모리 누수가 발생할 수 있는 경우는 다음과 같습니다. 

 

1) ViewModel 에서 Activity의 context나  Activity의 View 참조

- ViewModel에서 특정 액티비티 인스턴스보다 더 오랜 수명을 가질 수 있기 때문에 메모리 누수가 일어날 수 있습니다.

 

2) ViewBinding 사용시 Fragment에서 누수

override fun onDestroyView() {
    super.onDestroyView()
    _binding = null
}

뷰바인딩 사용시 위 코드를 사용하지 않으면 메모리릭이 발생합니다. 

 Fragment는 Fragment내의 View의 생명주기 더 오래 유지가 되기 때문에 생기는 일입니다.

 

오늘날은 크게 두가지의 경우가 있을 것 같습니다. 

요즘은 lifecycle 라이브러리를 많이 잘사용하면 자동적으로 메모리 누수를 방지가 잘되어있는 편입니다.

그래도 잊지말고 한번쯤 체크해보면 좋을거 같네요.

 

메모리 누수 문제는 오랫동안 안드로이드 개발자를 괴롭혀온 녀석입니다.

2021년 각 기기마다 OS로 부터 허락받는 메모리 크기도 많이 늘었겠지만

잊을만 하면 신경쓰이게 만드는 존재입니다.

 

메모리 누수와의 싸움은 안드로이드 개발자의 숙명이 아닐까 싶네요,,