내 앱은 메모리를 얼마나 쓸까? Android MEMINFO 완벽 분석 가이드

안드로이드 앱 개발자라면 누구나 한 번쯤은 마주치는 공포의 단어, ‘OutOfMemoryError(OOM)’. 사용자가 앱을 사용하던 중 갑자기 앱이 강제 종료되거나, 이유 없이 버벅거리는 현상을 겪는다면 그 뒤에는 ‘메모리’ 문제가 숨어있을 가능성이 높습니다.

이러한 문제를 해결하기 위한 첫걸음은 바로 내 앱이 메모리를 ‘어떻게’, 그리고 ‘얼마나’ 사용하는지 정확히 파악하는 것입니다. 안드로이드 시스템은 MEMINFO라는 강력한 도구를 통해 특정 시점의 애플리케이션 메모리 사용량에 대한 아주 상세한 스냅샷을 제공합니다.

오늘은 이 MEMINFO 로그를 단순한 숫자 나열이 아닌, 내 앱의 건강 상태를 진단하는 ‘진단서’처럼 읽어내는 방법을 자세히 알아보겠습니다. 각 항목의 의미를 넘어, 어떤 지표를 중점적으로 봐야 하는지 실질적인 분석 팁까지 함께 공유해 드리겠습니다.

MEMINFO란 무엇이며 어떻게 얻을 수 있나요?

MEMINFO는 특정 프로세스(애플리케이션)의 메모리 사용 현황을 상세하게 보여주는 텍스트 보고서입니다. 주로 아래 두 가지 방법으로 얻을 수 있습니다.

  1. 실시간 확인 (adb 사용): PC에 스마트폰을 연결하고 터미널에서 아래 명령어를 실행하면 현재 실행 중인 앱의 MEMINFO를 바로 확인할 수 있습니다. Shelladb shell dumpsys meminfo <패키지_이름_또는_PID>
  2. 버그 리포트(dumpstate) 분석: 사용자의 기기에서 ‘버그 리포트’를 추출하면, 해당 파일 내에 리포트 생성 시점의 모든 프로세스에 대한 MEMINFO 정보가 포함되어 있습니다. 현장에서 발생한 문제를 사후에 분석할 때 주로 사용됩니다.

이제 실제 MEMINFO 로그 예시를 보며 각 항목을 파헤쳐 보겠습니다.

** MEMINFO in pid 22565 [com.android.application.test] **
                   Pss      Pss   Shared  Private   Shared  Private  SwapPss      Rss     Heap     Heap     Heap
                 Total    Clean    Dirty    Dirty    Clean    Clean    Dirty    Total     Size    Alloc     Free
                ------   ------   ------   ------   ------   ------   ------   ------   ------   ------   ------
   Native Heap   15956        0     2764    15948        8        0     1921    18720    61936    11078    46627
   Dalvik Heap   11106        0     5836     9744     1164     1264        4    18008    27216     2640    24576
  ...
         TOTAL   38302     3644    40428    28384    54540     4916     3253   128268    89152    13718    71203

... (Dalvik Details, App Summary, Objects 등) ...

숲을 먼저 보기: 가장 중요한 상위 지표들

복잡한 숫자들 속에서 길을 잃지 않으려면, 가장 먼저 숲 전체를 봐야 합니다. MEMINFO 보고서의 가장 마지막 App Summary 섹션의 TOTAL PSS 값이 바로 그 숲에 해당합니다.

항목설명
Pss Total프로세스가 사용하는 메모리의 비례적 총량입니다. 공유 메모리를 중복 계산하지 않고, 프로세스가 실제로 사용하는 메모리만 반영합니다. 이 값은 프로세스의 메모리 사용량을 정확히 파악하는 데 유용합니다.
Pss Clean공유 메모리의 클린(Clean) 부분입니다. 클린 메모리는 디스크에 저장된 파일과 동일하며, 필요할 때 재사용할 수 있습니다.
Shared Dirty공유 메모리의 더티(Dirty) 부분입니다. 더티 메모리는 디스크에 저장되지 않은 변경된 메모리로, 프로세스 간에 공유되지만 중복 계산됩니다.
Private Dirty프로세스만 사용하는 더티 메모리입니다. 이 메모리는 프로세스가 독점적으로 사용하며, 디스크에 저장되지 않은 데이터를 포함합니다.
Shared Clean공유 메모리의 클린(Clean) 부분입니다. 여러 프로세스가 공유할 수 있으며, 디스크에 저장된 파일과 동일합니다.
Private Clean프로세스만 사용하는 클린 메모리입니다. 디스크에 저장된 파일과 동일하며, 필요할 때 재사용할 수 있습니다.
SwapPss Dirty스왑된 메모리의 비례적 크기 중 더티(Dirty) 부분을 나타냅니다. 스왑은 물리 메모리 부족 시 디스크로 옮겨진 메모리를 의미하며, 더티 메모리는 변경된 데이터를 포함합니다.
Rss (Resident Set Size) Total프로세스가 사용 중인 물리 메모리의 총량입니다. 공유 메모리가 중복 계산될 수 있으므로, 실제 물리 메모리 사용량을 파악하는 데 사용됩니다.
Heap Size애플리케이션에 할당된 힙 메모리의 총 크기입니다. 이 값은 JVM 또는 네이티브 힙에서 관리되는 전체 메모리 공간을 나타냅니다.
Heap Alloc실제로 사용된 힙 메모리입니다. 힙에서 현재 할당된 객체 또는 데이터의 크기를 나타냅니다.
Heap Free사용 가능한 여유 힙 메모리입니다. 힙에서 아직 사용되지 않은 가용 메모리 공간을 나타냅니다.
  • Pss (Proportional Set Size): 한 프로세스가 사용하는 메모리 양을 가장 합리적으로 측정한 값입니다. 안드로이드에서는 여러 앱이 시스템 라이브러리 등 메모리 공간을 ‘공유’해서 사용하는데, Pss는 이 공유 메모리를 공유하는 프로세스 수로 나누어 공평하게 계산합니다. 따라서 여러 앱의 Pss를 모두 더하면 시스템의 전체 실제 메모리 사용량과 거의 근사해집니다.
    • Key Point: 메모리 사용량을 평가할 때는 TOTAL PSS 값을 가장 중요한 기준으로 삼아야 합니다. 이 값이 내 앱의 실질적인 메모리 점유율입니다.
  • Rss (Resident Set Size): 해당 프로세스가 현재 사용 중인 물리 메모리(RAM)의 총량입니다. 공유 메모리가 중복으로 계산될 수 있어, 여러 프로세스의 RSS를 단순히 더하면 실제 물리 메모리보다 훨씬 큰 값이 나올 수 있습니다. Pss와 함께 참고용으로 활용합니다.

나무를 보기: 메모리는 어디에 사용되고 있을까? (App Summary 분석)

TOTAL PSS로 전체적인 규모를 파악했다면, 이제 App Summary 섹션을 통해 그 메모리가 구체적으로 어디에 사용되고 있는지 살펴볼 차례입니다. 이 부분은 개발자가 이해하기 쉬운 카테고리로 메모리 사용 내역을 요약해 주어 문제의 원인을 파악하는 데 결정적인 단서를 제공합니다.

항목설명
Java Heap자바/코틀린 코드로 작성된 객체들이 저장되는 공간입니다. 대부분의 안드로이드 개발자가 주로 다루는 영역으로, 이 값이 비정상적으로 높다면 관리 코드 내에 메모리 누수(Memory Leak)가 있을 가능성이 큽니다.
Native HeapC/C++ 같은 네이티브 코드가 사용하는 메모리 공간입니다. 게임 엔진, 그래픽 라이브러리, 또는 JNI(Java Native Interface)를 통해 네이티브 코드를 사용하는 경우 이 수치가 높아집니다. 여기서 발생하는 누수는 추적하기가 더 까다로울 수 있습니다.
Code.dex, .so, .art 파일 등 앱의 실행 코드 자체가 차지하는 메모리입니다. 앱의 크기가 크거나, 많은 라이브러리를 사용하면 이 값이 커집니다.
Stack각 스레드별로 할당된 스택 메모리입니다. 함수 호출, 지역 변수 등이 저장됩니다.
Graphics그래픽 렌더링(UI, OpenGL 버퍼 등)과 관련된 메모리입니다. 복잡한 UI나 애니메이션이 많을수록 증가합니다.
Private Other / System위의 카테고리에 속하지 않는 기타 메모리 및 시스템 관련 리소스 사용량입니다.

“내 앱의 PSS가 비정상적으로 높은데, 그 원인이 Java Heap에 있을까, 아니면 Native Heap에 있을까?” 이 질문에 답하는 것이 메모리 분석의 첫 단추입니다.

더 깊은 단서 찾기: 세부 항목별 분석 팁

원인이 되는 메모리 영역을 특정했다면, 이제 더 깊은 단서를 찾아 나설 차례입니다.

Objects – 메모리 누수의 흔적

보고서의 Objects 섹션은 현재 메모리에 살아있는 주요 안드로이드 컴포넌트 객체의 수를 보여주어 메모리 누수를 진단하는 데 매우 유용합니다.

항목설명
Views애플리케이션에서 생성된 UI 뷰(View) 객체의 수를 나타냅니다. 뷰의 수가 많다면, UI가 복잡하거나 메모리 누수가 발생하고 있을 수 있습니다. 뷰의 과도한 생성은 메모리 사용량을 증가시킬 수 있습니다.
AppContexts애플리케이션 컨텍스트(AppContext) 객체의 수를 나타냅니다. 컨텍스트는 리소스, 설정 등에 접근하기 위해 사용됩니다. 컨텍스트의 수가 많다면, 불필요한 컨텍스트가 유지되고 있거나 메모리 누수가 발생하고 있을 수 있습니다.
Assets애플리케이션에서 열린 자산(Asset) 객체의 수를 나타냅니다. 자산은 APK 내부에 포함된 파일(예: 이미지, 텍스트 파일 등)을 참조합니다. 자산 객체가 많다면, 불필요한 파일을 열었거나 메모리 누수가 발생하고 있을 수 있습니다.
Local Binders로컬 바인더 객체의 수를 나타냅니다. 바인더는 프로세스 간 통신(IPC)을 위해 사용됩니다. 바인더 객체가 많다면, IPC가 과도하게 발생하거나 메모리 누수가 발생하고 있을 수 있습니다.
Parcel memoryParcel 객체가 사용 중인 메모리의 양을 나타냅니다. Parcel은 IPC 통신을 위한 데이터 컨테이너입니다. 이 값이 크다면, IPC 통신이 빈번하거나 메모리 누수가 발생하고 있을 수 있습니다.
Death RecipientsDeath Recipient는 Android 10 이후 제거된 개념입니다. 최신 버전에서는 이 항목이 표시되지 않습니다. 프로세스가 종료될 때 알림을 받는 객체의 수를 나타냈습니다. 이 값이 크다면, 프로세스 종료를 감시하는 객체가 많음을 의미했습니다.
ViewRootImplViewRootImpl 객체의 수를 나타냅니다. ViewRootImpl은 UI 트리의 루트를 관리하며, 화면 렌더링을 담당합니다. 이 값이 크다면, 여러 화면(Activity 또는 Dialog)이 동시에 열려 있거나 메모리 누수가 발생하고 있을 수 있습니다.
Activities애플리케이션에서 생성된 액티비티(Activity) 객체의 수를 나타냅니다. 액티비티의 수가 많다면, 화면이 과도하게 생성되었거나 메모리 누수가 발생하고 있을 수 있습니다.
AssetManagersAssetManager 객체의 수를 나타냅니다. AssetManager는 애플리케이션의 자산(Asset)에 접근하기 위해 사용됩니다. 이 값이 크다면, 불필요한 AssetManager가 생성되었거나 메모리 누수가 발생하고 있을 수 있습니다.
Proxy Binders프록시 바인더 객체의 수를 나타냅니다. 프록시 바인더는 원격 프로세스와 통신하기 위해 사용됩니다. 이 값이 크다면, 원격 IPC 통신이 빈번하거나 메모리 누수가 발생하고 있을 수 있습니다.
Parcel countParcel 객체의 수를 나타냅니다. Parcel은 IPC 통신을 위한 데이터 컨테이너입니다. 이 값이 크다면, IPC 통신이 빈번하거나 메모리 누수가 발생하고 있을 수 있습니다.
WebViews애플리케이션에서 생성된 WebView 객체의 수를 나타냅니다. WebView는 웹 콘텐츠를 표시하는 데 사용됩니다. WebView는 메모리를 많이 사용하므로, 이 값이 크다면 메모리 사용량이 크게 증가할 수 있습니다.
  • Views / ViewRootImpl / Activities / AppContexts: 이 값들은 각각 화면을 구성하는 뷰, 액티비티, 컨텍스트 등의 개수입니다. 사용자가 특정 화면을 닫고 다른 화면으로 이동했는데도 이 값들이 줄어들지 않고 계속해서 증가한다면, 이전에 사용했던 화면의 객체들이 메모리에서 해제되지 않고 남아있는 ‘메모리 누수’를 강력하게 의심해볼 수 있습니다.

Dalvik Details – Java 힙 심층 분석

이 섹션은 Java Heap을 더욱 세분화하여 보여줍니다. 예를 들어, .LOS(Large Object Space) 항목의 수치가 크다면 앱에서 비트맵 이미지나 대용량 배열 같은 큰 객체를 많이 사용하고 있다는 신호일 수 있습니다.

Native Allocations – 네이티브 메모리 사용처

이 항목은 Native Heap의 사용 내역을 더 자세히 보여줍니다. 특히 Bitmap (malloced) 항목을 통해 비트맵 이미지가 네이티브 메모리를 얼마나 사용하는지 파악할 수 있어, 이미지 관련 메모리 문제를 진단할 때 유용합니다.

마치며

MEMINFO는 처음 보면 암호문처럼 보이지만, 그 구조와 각 항목의 의미를 이해하고 분석의 흐름을 잡으면 내 앱의 메모리 상태를 진단할 수 있는 가장 강력한 진단서가 됩니다.

앱의 성능 저하나 잦은 비정상 종료로 고민하고 있다면, 가장 먼저 dumpsys meminfo를 통해 Total PSS 값을 확인하고, App Summary를 통해 Java HeapNative Heap 중 어디에 문제가 있는지 범위를 좁혀보세요. 그리고 Objects 섹션을 통해 액티비티나 뷰의 누수가 의심되는 정황은 없는지 확인하는 습관을 들인다면, 훨씬 더 안정적이고 쾌적한 고품질의 앱을 만드는 데 큰 도움이 될 것입니다.

읽어주셔서 감사합니다. 🙂

"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."

댓글 달기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

위로 스크롤