티스토리 뷰

728x90
반응형

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 >




반응형
공지사항
최근에 올라온 글