Regular Motion

개발자가 상팔자

[Android] How to Leak a Context: Handlers & Inner Classes

이 글은 www.androiddesignpatterns.com에 소개된 글을 저자의 동의를 얻고 번역한 것임을 알려드립니다.

원문 : http://www.androiddesignpatterns.com/2013/01/inner-class-handler-memory-leak.html

 

위의 코드는 괜찮아 보일지 몰라도 상당한 양의 메모리 릭을 발생시킬 수 있다.

그리고 Android Lint는 “In Android, Handler classes should be static or leaks might occur.”라는 Warning을 보여줄 것이다. 그럼 어디서 메모리 릭이 발생할 수 있는지 알아보자.

1. Android Application이 실행될 때, Framework에서는 Application의 메인 쓰레드를 위한 Looper Object를 생성한다. Looper는 단순한 메시지 큐를 생성하여 Message들을 처리하고, Application의 Lifecycle과 동일한 Lifecycle을 갖는다.

2. 메인 쓰레드에서 생성된 Handler는 Looper의 메시지 큐에 속하게 된다.  메시지 큐로 보내진 Message들은 Handler에 대한 reference를 갖고 있어야만, Looper가 해당 메시지를 처리할 수 있다.   Looper가 메시지를 처리할 때 Handler#handleMessage(Message)를 호출해야 하기 때문.

3. Java에서는 non-static inner class와 anonymous class는 outer class에 대한 implicit reference를 갖고, static inner class의 경우에는 갖지 않는다.

 

위의 코드에서는 Activity가 종료되더라도, Delayed Message는 처리되기 전까지 메인 쓰레드의 메시지 큐에 10분간 남아있을 것이다. 이때 Delayed Message는 Handler에 대한 reference를 갖고 있고, Handler는 outer class에 대한 reference를 갖고 있다. 위의 예에서 outer class는 SampleActivity에 해당한다. 따라서 Message가 처리되기 전까지 SampleActivity에 대한 reference가 남아있기 때문에, Activity가 종료되었다 하더라고 Activity Context는 Garbage Collect될 수 없게 된다.

거의 동일한 이유로 anonymous Runnable class도 Activity Context가 Garbage Collect되는 것을 방해한다.

 

위 문제를 해결하기 위해서는 Handler를 static inner class로 정의하거나, 새로운 파일에 subclass해야 한다. static inner class는 outer class에 대한 implicit reference를 갖기 않기 때문에 Activity Context가 Garbage Collect되는 것을 방해하지 않을 것이다.

만약 Handler 내부에서 Activity의 method를 호출해야 할 경우 Activity의 WeakReference를 갖도록 한다.

 

 

static inner class와 non-static inner class는 큰 차이가 없는 것 같지만, 실제로는 모든 Android 개발자들이 이해해야 하는 중요한 부분이다.

만약 inner class가 Activity의 Lifecycle에 종속적이지 않다면, non-static inner class로 선언하지 말고, static inner class로 선언한 뒤, weak reference를 갖도록 하자.

 

답글 남기기

© 2017 Regular Motion

Theme by Anders NorenUp ↑