본문 바로가기

ANDROID/Performance

[안드로이드] 구글이 소개하는 메모리 최적화 기법들을 리뷰해보자

이미지 출처 : https://appachhi.com/blog/optimizing-memory-android-apps/

안드로이드 개념 공부를 하던 중에 앱 메모리 관리라는 페이지를 찾게 되었는데, 상당히 유용한 정보들과

 

어떠한 기술들이 실질적으로 어떤 이점을 가져다주는지 등에 대한 내용들이 있어 포스팅에 좋을 것 같다고 생각했다.

 

공식 문서가 소개하는 내용들 중 핵심적으로 정리하고자 하는 내용들을 써보고자 한다.

 

 


 

1.  onTrimMemory callback의 활용

 

import android.content.ComponentCallbacks2
// Other import statements ...

class MainActivity : AppCompatActivity(), ComponentCallbacks2 {

    // Other activity code ...

    /**
     * Release memory when the UI becomes hidden or when system resources become low.
     * @param level the memory-related event that was raised.
     */
    override fun onTrimMemory(level: Int) {

        // Determine which lifecycle or system event was raised.
        when (level) {

            ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN -> {
                /*
                   Release any UI objects that currently hold memory.

                   The user interface has moved to the background.
                */
            }

            ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE,
            ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW,
            ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL -> {
                /*
                   Release any memory that your app doesn't need to run.

                   The device is running low on memory while the app is running.
                   The event raised indicates the severity of the memory-related event.
                   If the event is TRIM_MEMORY_RUNNING_CRITICAL, then the system will
                   begin killing background processes.
                */
            }

            ComponentCallbacks2.TRIM_MEMORY_BACKGROUND,
            ComponentCallbacks2.TRIM_MEMORY_MODERATE,
            ComponentCallbacks2.TRIM_MEMORY_COMPLETE -> {
                /*
                   Release as much memory as the process can.

                   The app is on the LRU list and the system is running low on memory.
                   The event raised indicates where the app sits within the LRU list.
                   If the event is TRIM_MEMORY_COMPLETE, the process will be one of
                   the first to be terminated.
                */
            }

            else -> {
                /*
                  Release any non-critical data structures.

                  The app received an unrecognized memory level value
                  from the system. Treat this as a generic low-memory message.
                */
            }
        }
    }
}

ComponentCallback2라는 인터페이스를 상속하는 경우 onTrimMemory callback을 사용할 수 있게 된다.

 

요즘에는 고사양 기기들이 다수 등장해 메모리 관련 이슈에 대해 고민이 덜 필요할 수도 있으나, 안드로이드가 항상 직면하는 기기의 파편화, 성능의 파편화를 따졌을 때, 조금이라도 더 많은 사용자가 서비스를 원활하게 활용하기 위해서는 메모리 관리는 지금도, 그리고 여전히 필수적이라 할 수 있다. (많은 메모리를 사용하는 작업이라면 더욱)

 

이 onTrimMemory callback을 통해 개발자는 사용 가능한 메모리의 양을 체크해 그 수준에 따라 수행하고자 하는 작업들을 할당할 수 있게 된다.

 

이를테면 메모리의 양이 충분히 사용 가능한 경우, 많은 양의 메모리를 필요로 하는 작업을 그대로 수행하게 할 수 있고, 반대의 경우라면 기존 앱의 작업들 중 메모리를 많이 잡아먹는 기능들을 멈춰 GC를 통해 메모리 확보가 되도록 수행할 수 있는 것이다.

 

2. 사용이 끝난 Service는 종료하자

 

Service가 특정 작업을 수행한 이후 별도의 종료 작업을 하지 않으면 프로세스에 그대로 유지되면서 서비스가 참조하고 있던 여러 요소들로 인해 Memory Leak이 발생할 수 있다. 문서 내용과 별도로 경우에 따라서만 수행해야 하는 작업이라면 Service 대신 IntentService를 활용하는 것도 한 가지의 방법이 되겠다.

 

3. 추상화 클래스는 필요한 만큼 사용하자

 

보통 추상화 클래스들은 다양한 개발 이점을 위해 사용되고는 하는데, 이 추상화 클래스를 이용해 만들어진 코드들의 경우 실행되는 시점에 추상화 클래스를 사용하지 않은 코드에 비해 좀 더 많은 시간과 메모리를 소모한다고 한다. 문서를 읽던 중에 약간 의외라고 생각했던 지점이기도 하다. 왜냐하면 개발하던 중에 성능상의 영향을 줄 것이라는 생각을 하지 않았기 때문 (이쯤되면 반성이 필요한 부분)

 

4. 메모리 휘젓기(?) 조심하기 

 

Avoid Memory churn이라고 소개하고 있는 이 부분은 특정 작업에 대한 과도한 메모리 allocation을 경고하고 있다. allocation이 지속적으로 이루어지고, 이것이 참조되지 않는 시점이라면 GC가 수행될 것인데 문제점은 GC가 실행 될 때 앱 프레임레이트에 영향을 준다는 점이다.

 

이를테면 연속적으로 프레임을 그려야하는 작업이 있고, 여기에서 필요한 바이트 배열을 프레임마다 생성하고 있었다면 메모리 프로파일러로 메모리 그래프를 보는 순간 파도처럼 요동치고 있는 모습을 볼 수 있을 것이다.

 

과한 allocation, 불필요한 allocation이 일어나는 지점을 주의하자!

 

5. APK 사이즈를 줄이자

 

앱을 실행한 다음 메모리 프로파일링을 해 보면 기타 코드 이외에도 그래픽 리소스가 메모리를 잡아먹고 있는 것을 확인할 수 있을 것이다. APK 사이즈에 영향을 주는 요소들이 다양하게 있겠지만, 이들의 사이즈를 줄이는 것 만으로 앱이 기본적으로 사용하는 메모리의 양을 줄일 수 있으므로 앱 설치파일 사이즈를 줄이는 것을 구글은 권장하고 있다. (기기에서 얼마만큼의 설치공간을 차지하는지에서 끝나는 얘기가 아닌 것이다.) 

 

번외로 앱이 업데이트가 되면 될 수록 설치되는 기기의 수가 줄어들었던 보고서도 있으니, 이런점에 있어서도 설치파일 및 앱 사이즈를 줄이는 것은 중요하다고 볼 수 있다.(개인적으로 설치 기기 수가 줄어드는 원인은 지속적으로 기기를 사용하는 경우 기기 용량이 가득 찬 사용자들이 다수 생길 수 있기 때문이라고 본다.)

 

6. Dagger2를 쓰자

 

DI가 가능한 라이브러리는 여러가지가 있지만, 문서 작성의 시점때문인지 몰라도 Dagger2를 콕 집어서 쓰라고 구글은 권장하고 있다. 단순한 코드들 간의 디커플링을 돕는 것 이외에도 컴파일 시간 및 코드를 참조하는 방식이 기존 대비 뛰어나고 절약적이라고 한다. '왜' 그런지에 대해서는 조금 더 공부가 필요할 듯.

 

7. 외부 라이브러리를 너무 함부로 쓰지 말자

 

앱 개발을 돕는 라이브러리들은 정말 방대하고 다양하지만, 개발자는 상당 부분에서 라이브러리의 내부 코드를 변경할 수 없는 부분이 있고, 사용하는 라이브러리가 코드 및 성능상의 최적화가 잘 이루어져 있다고 보장할 수 도 없다. 그러한 점에서 '검증된' 라이브러리를 사용하는 것은 굉장히 중요하다고 볼 수 있겠다.

 

 

 

이외에도 다수의 내용이 있고, 이 문서의 내용을 토대로 좀 더 공부해 들어갈 수 있는 요소들이 많아 그동안 봤던 문서들 중에 꽤나 유용한 쪽에 속한다고 본다.

 

이후에는 Dagger2 및 Koin, 최근 등장한 Hilt에 대한 공부 및 포스팅을 진행해보면 좋을 듯 싶다! 👍

 

* 잘못된 부분 혹은 개선 가능한 부분들에 대해서는 언제든지 피드백 바랍니다 :) *

 

< 참조 >

 

앱 메모리 관리  |  Android 개발자  |  Android Developers

RAM(Random Access Memory)은 모든 소프트웨어 개발 환경에서 중요한 리소스이지만 실제 메모리의 제약이 많은 모바일 운영체제에서는 더욱 중요합니다. Android 런타임(ART)과 Dalvik 가상 머신에서 일상적

developer.android.com