티스토리 뷰
Avoiding Memory Leaks
안드로이드 애플리케이션은, 적어도 T-Mobbile G1 에서는 16MB의 힙으로 제한된다.
그것은 전화를 위한 많은 메모리이고 개발자가 달성하기를 원하는것에는 거의 없다.
이 메모리를 모두 사용하지 않는 경우에도, 다른 응용프로그램을 죽이지 않고 실행할 수 있게 하려면 가능한 작게 사용해야 한다.
Android가 메모리에 보관할 수 있는 응용프로그램이 많을수록 사용자가 응용프로그램을 전환하는 속도가 빨라진다.
내 작업중에 안드로이드 애플리케이션에서 메모리 누출 문제가 발생했고, 같은 실수로 대부분의 시간을 보냈다. ( Context에 대한 장기간의 레퍼런스를 유지)
안드로이드에서 Context는 많은 연산에 사용되지만 대부분은 리소스를 로드하고 액세스한다.
이것은 모든 위젯이 생성자에서 Context 매개 변수를 받는 이유이다.
일반 안드로이드 응용 프로그램에서 일반적으로 Activity, Application 두 가지 종류의 Context를 가지고 있다.
이것은 일반적으로 개발자가 Context가 필요한 메소드나 클래스를 전달하는 방법이다.
@Override
protected void onCreate( Bundle state) {
super.onCreate( state );
TextView label = new TextView(this);
label.setText(”Leaks are bad”);
setContentView(label);
}
이는 뷰가 전체 활동을 참조하므로 사용자의 Activity가 보유하고있는 모든 것을 참조함을 의미한다. ( 일반적으로 전체 View 계층과 모든 리소스 )
따라서 Context가 누수된 경우, “누수”의 의미는 레퍼런스를 계속 유지하여 GC를 수집하지 못하게 하는것, 많은 메모리가 누출된다.
조심하지 않으면 전체 activity를 누출하는 것이 정말 쉬워진다.
화면 방향이 변경되면 시스템은 기본적으로 현재 activity를 삭제하고 상태를 유지하면서 새 activity를 만든다.
이렇게 하면 Android는 리소스에서 애플리케이션의 UI를 다시 로드한다.
이제 매번 회전할 때마다 로드하지 않는 큰 bitmap을 사용하여 응용 프로그램을 작성했다고 가정해보자.
매 회전마다 다시 로드할 필요가 없도록 유지하는 가장 쉬운 방법은 정적 필드를 유지하는 것이다.
private static Drawable sBackground;
@Override
protected void onCreate ( Bundle state ) {
super.onCreate ( state );
Textview label = new TextView(this);
label.setText(”Leaks are bad”);
if(sBackground == null) {
sBackground = getDrawable(R.drawable.large_bitmap);
}
labe.setBackgroundDrawable(sBackground);
setContentView(labe);
}
이 코드는 매우 빠르며 매우 잘못 되었다.
첫 번째 화면 방향 변경시 작성된 첫 번째 activity가 유출된다. Drawable이 view에 붙을때, view는 drawable의 콜백으로 설정된다.
위의 코드 예에서 drawable은 Textview 자체에 대한 참조를 가지고 있으며, 그 자체가 activity ( context )에 대한 레퍼런스를 가지고 있다는 것을 의미한다.
이 예제는 가장 간단한 누수 사례 중 하나이며, activity가 소멸될 때 저장된 drawable의 콜백을 null로 설정하여 홈 스크린 소스코드 ( unbindDrawables() 메소드 찾아보기 ) 에서 Context를 어떻게 처리했는지 확인 할 수 있다.
흥미롭게도 누출 된 context chain을 만들 수 있는 경우가 있다. 그들은 당신이 오히려 빨리 추리하게 만든다.
문맥 관련 메모리 누수를 피하는 두 가지 쉬운 방법이 있다.
가장 확실한 방법은 자신의 범위 밖에서 Context를 벗어나는 것을 피하는 것이다.
위의 예는 정적 참조의 경우를 보여주지만 내부 클래스와 외부 클래스에 대한 암시적 참조는 똑같이 위험할 수 있다.
두 번째 해결 방법은 Application Context 를 사용하는 것이다.
이 context는 애플리케이션이 살아있고 activity life-cycle에 의존하지 않는 한 계속 존재한다.
context가 필요한 수명이 긴 개체를 유지하려는 경우 응용 프로그램 개체를 기억하자.
Context.getApplicationContext() 또는 Activity.getApplication()을 호출하면
쉽게 얻을 수 있다.
context관련 메모리 누수를 방지하려면 다음을 기억하자
- context-activity에 대한 수명이 긴 참조를 유지하지 마시오
(activity 참조는 activity 자체와 동일한 수명주기를 가져야 한다 )
- context-activity 대신 context-application을 사용해보자
- life-cycle을 제어하지 않고 정적 내부 클래스를 사용하고 내부 activity에 대한 weak reference를 작성하는 경우, 비 정적 내부 클래스를 피하라.
이 문제에 대한 해결 방법은 외부 클래스에 WeakReference가 있는 정적 내부 클래스를 사용하는 것이다.
- GC는 메모리 누수에 대한 보험이 아니다
+
Reference
< https://android-developers.googleblog.com/2009/01/avoiding-memory-leaks.html >
'프로그래밍 > Android' 카테고리의 다른 글
[Android] Fragment add(), replace(), BackStack (0) | 2017.12.25 |
---|---|
[Android] Hide FAB on scroll (0) | 2017.12.24 |
[Android.Error] failed to resolve : android.arch (0) | 2017.11.30 |
FCM, GCM (0) | 2017.11.16 |
[Android] static member accessed via instance reference (0) | 2017.11.09 |