[ Android ] Context 와 메모리 릭
📌 주요 기능
- 어플리케이션에 관하여 시스템이 관리하고 있는 정보에 접근
- 리소스, db, preference 접근 : getResourece() …
- package 위치 인식 : getPackageName()
- 안드로이드 시스템 서비스에서 제공하는 API 호출하기
- 엑티비티 및 서비스 실행 : startAcitivity(), startService()
- 시스템 서비스 접근 : getSystemService
- 안드로이드가 제공하는 시스템-레벨 서비스의 메너저 객체를 반환 받을 수 있다.
📌 Context 의 종류와 사용시 주의점
Context 의 종류
📍 Application Context
- 싱글턴 인스턴스
- getApplicationContext 를 통해 접근가능
- Application 라이프사이클에 의존함
📍 Base Context
- Activity 나 Service 내에서 유효한 context 이다.
- Activity 에 대응하는 context 를 Activity Context 로 칭한다.
- Activity, Service 라이프 사이클을 따른다.
사용시 주의점 : Memory Leak
싱글턴 오브젝트를 생성하고 이때 컨텍스트가 필요하다면 AcitivityContext가 아닌 ApplicationContext 를 주입해야합니다. Acitivity Context 를 주입할 경우 해당 Acitiviity가 destory 되더라도 싱글턴 오브젝트에서 사용하고 있으므로 ActivityContext 가 Garbage Collection 이 진행되지 않아 memory leak 이 발생합니다.
또한 ViewModel 에서 ActivityContext 를 넘겨받는 잘못된 경우를 생각해볼 수 있습니다. ViewModel 은 Activity 보다 긴 생명주기를 갖게되고 Activity가 Destory 상태에 도달하더라도 ViewModel 의 참조로 인해서 ActivityContext 는 GC 에 의해 메모리 해제되지 않아 메모리 릭이 발생하게 됩니다
결론적으로 안드로이드에서는 생명주기가 짧은 쪽에서 긴쪽의 사용하는 것이 메모리 릭을 막을 수 있는 방법입니다.
그렇다면 모든 상황에서 ActivityContext 보다 생명주기가 긴 ApplicationContext 를 사용하면 안전할까요?
그렇지 않습니다. Dialog, Toast 등 화면 관련된 부분은 Activity Context 를 사용해야합니다.
메모리 릭에 대해서는 아래 두 가지 툴을 통해 진행할 수 있습니다.
https://github.com/square/leakcanary
GitHub - square/leakcanary: A memory leak detection library for Android.
A memory leak detection library for Android. Contribute to square/leakcanary development by creating an account on GitHub.
github.com
https://developer.android.com/studio/profile/memory-profiler?hl=ko
메모리 프로파일러를 사용하여 앱의 메모리 사용량 검사 | Android 개발자 | Android Developers
끊김 현상, 멈춤, 심지어 비정상 종료를 일으킬 수 있는 메모리 누수 및 메모리 변동을 식별하는 데 도움이 되는 Android 프로파일러의 메모리 프로파일러 구성요소를 알아보세요.
developer.android.com
Context 심층 탐구
📌 Context 의 구성
Application, Activity, Service 는 Context 를 상속하고 있으며 위에 포함되지 않은 4대 Component 들인 ContentProvider 와 BroadcastReceiver 또한 context 를 사용합니다.
또한 Context 튼 ConextWrapper 는 내부적으로 Context 객체를 들고 있고 모든 동작을 Context 구현체의 함수로 위임하게 됩니다.(decorate 디자인패턴)
위 와같은 구현의 장점은 내부 구현체(객체)가 바뀐다 하더라도 Context 를 사용하는 방식(사용 메서드) 는 그대로 유지할 수 있습니다. 또한 잘못된 방식으로의 Context 의 사용이나 변경을 막을 수도 있습니다.
📌 왜 Context 필요할까?
context 가 필요한 근본적인 이유에 대해서 생각해보았습니다.
위에 말한 2가지 기능에서 Application 전역적인 정보에 대한 바로 접근하던 시스템 서비스의 api 를 사용하던 안드로이드 시스템에 직접 접근하면 될텐데 왜 중간에 Context 라는 개념이 존재할까라는 context 의 존재에 대한 의문을 갖게 되었습니다.
(예: 접근시에는 System.getPackageName() 으로 구성하면 편할 텐데 왜this.getApplicationContext.getPackageName() 으로 접근해야함)
그 이유는 안드로이드 플렛폼에선 어플리케이션과 프로세스가 별도로 관리되어지며 각각의 어플리케이션은 AcitivityManagerService 라는 일종에 다른 어플리케이션을 통해 관리 되어 지기 때문입니다.
AcitivityManagerService 에서는 어플리케이션을 특정 토큰을 키값으로 ‘key-value’ 쌍으로 관리하게 되고 이에 따라 자신이 어떤 어플리케션인지를 알려주는 즉 key 를 담는 객체가 필요합니다. 여러 앱을 관리하기에 어떤 앱으로 부터의 요청인지 알기 위해서 입니다. 이러한 AcitivityManagerServcie 로의 접근을 가능하게 하는 통로 역할을 수행하는 것이 바로 context 라고 할 수 있습니다.
마지막으로 정리하면 Android OS 는 어플리케이션과 프로세스가 1:1 대응하는 구조가 아닙니다.
중간에 ActivityManagerService 를 통해 여러 앱이 관리되어진다.
이에따라 어플리케이션 정보를 얻기 위해서는 자신이 어떤 앱인지 ActivityManagerService에게 알려줄 수 있는 context 가 필요하다