Skip to content

Most visited

Recently visited

navigation

Memory Profiler로 Java 힙 및 메모리 할당 보기

Memory Profiler는 Android Profiler의 한 구성 요소로서, 버벅거림, 멈춤, 심할 경우 앱의 비정상 종료로 이어질 수 있는 메모리 누수와 메모리 변동을 파악하는 데 도움이 됩니다. 앱의 메모리 사용 현황을 실시간 그래프로 보여주고, 힙 덤프를 캡처할 수 있게 해주고, 가비지 수집을 강제 실행하며, 메모리 할당을 추적합니다.

Memory Profiler를 열려면 다음 단계를 따르세요.

  1. View > Tool Windows > Android Profiler를 클릭합니다(툴바에서 Android Profiler 를 클릭해도 됨).
  2. Android Profiler 툴바에서 프로파일링하려는 기기 및 앱 프로세스를 선택합니다. USB를 통해 기기를 연결했는데 목록에 표시되지 않을 경우 USB 디버깅을 활성화했는지 확인하세요.
  3. MEMORY 타임라인의 아무 곳이나 클릭하면 Memory Profiler가 열립니다.

또는 dumpsys로 명령줄에서 앱 메모리를 검사할 수 있고 logcat에서 GC 이벤트를 확인할 수도 있습니다.

앱 메모리를 프로파일링해야 하는 이유

Android는 관리되는 메모리 환경을 제공합니다. 그래서 Android는 앱에서 어떤 객체를 더 이상 사용하지 않는다고 판단하면 가비지 수집기가 미사용 메모리를 다시 힙에 내놓습니다. Android가 미사용 메모리 찾기를 시작하는 방법은 꾸준히 개선되고 있지만, 모든 Android 버전의 어떤 지점에서는 시스템이 개발자의 코드를 잠깐 일시 중지해야 합니다. 대부분의 경우, 이러한 일시 중지는 감지할 수 없는 수준입니다. 하지만 앱이 시스템에서 수집할 수 있는 속도보다 빠르게 메모리를 할당하는 경우 수집기가 할당 요청을 충족시킬 만큼 충분한 메모리를 확보하는 동안 앱이 지연될 수 있습니다. 이런 지연으로 인해 앱이 프레임을 건너뛰고 눈에 띄게 느려질 수 있습니다.

앱이 속도 저하를 표시하지 않더라도 메모리 누수가 발생할 경우 앱이 백그라운드에 있는 동안에도 그 메모리를 유지할 수 있습니다. 이런 동작으로 인해 불필요한 가비지 수집 이벤트를 강제하게 됨으로써 시스템의 메모리 성능 중 나머지 부분이 저하될 수 있습니다. 결국, 시스템으로서는 메모리를 확보하려고 앱 프로세스를 종료할 수밖에 없습니다. 이후에 사용자가 앱으로 돌아올 때 앱을 완전히 다시 시작해야 합니다.

이런 문제를 예방하려면 Memory Profiler를 사용하여 다음 작업을 수행해야 합니다.

앱의 메모리 사용량을 줄일 수 있는 프로그래밍 방법에 대한 자세한 내용은 앱의 메모리 관리를 참조하세요.

Memory Profiler 개요

Memory Profiler를 처음 열면 앱의 메모리 사용 현황을 자세히 보여주는 타임라인과 가비지 수집을 강제 실행하고 힙 덤프를 캡처하고 메모리 할당을 기록하기 위한 액세스 도구가 보일 것입니다.

그림 1. Memory Profiler

그림 1에 표시된 것처럼, Memory Profiler의 기본 뷰에는 다음 사항이 포함됩니다.

  1. 가비지 수집 이벤트를 강제 적용하는 버튼
  2. 힙 덤프를 캡처하는 버튼
  3. 메모리 할당을 기록하는 버튼. Android 7.1 또는 이전 버전을 실행 중인 기기에 연결되어 있을 때만 이 버튼이 나타납니다.
  4. 타임라인을 확대/축소하는 버튼
  5. 라이브 메모리 데이터로 앞으로 이동하는 버튼
  6. activity 상태, 사용자 입력 이벤트 및 화면 회전 이벤트를 표시하는 이벤트 타임라인
  7. 다음을 포함하는 메모리 사용 타임라인
    • 각 메모리 범주에서 사용 중인 메모리의 양을 보여주는 누적 그래프로, 왼쪽의 y축에 메모리 양이 표시되며 맨 위에 색상 키가 표시됩니다.
    • 파선은 할당된 객체의 수를 나타내는데 오른쪽의 y축에 표시됩니다.
    • 각 가비지 수집 이벤트에 대한 아이콘

하지만 Android 7.1 또는 이전 버전을 실행 중인 기기를 사용하는 경우에는 기본적으로 일부 프로파일링 데이터가 표시되지 않습니다. "Advanced profiling is unavailable for the selected process"라는 메시지가 나타나면 고급 프로파일링을 활성화 하여 다음 사항을 확인해야 합니다.

Android 8.0 이상에서는 디버그 가능한 앱에 대해 고급 프로파일링이 항상 활성화됩니다.

메모리 카운트 방법

Memory Profiler(그림 2) 맨 위에 보이는 숫자는 Android 시스템에 따라 앱이 커밋한 모든 개인 메모리 페이지 수를 기준으로 합니다. 시스템이나 다른 앱과 공유하는 페이지는 이 수에 포함되지 않습니다.

그림 2. Memory Profiler의 맨 위에 있는 메모리 카운트 범례

메모리 카운트의 범주는 다음과 같습니다.

이전의 Android Monitor 도구에서 확인되는 메모리 카운트와 비교해 볼 때, 새로운 Memory Profiler는 메모리를 다르게 기록하므로 메모리 사용량이 더 많은 것처럼 보일 수 있습니다. Memory Profiler는 몇몇 범주를 더 모니터링하므로 메모리 총량이 늘어나지만, Java 힙 메모리에만 관심이 있다면 "Java" 숫자가 이전 도구에서 확인한 값과 비슷할 것입니다.

Java 숫자는 아마 Android Monitor에서 본 숫자와 정확히 일치하지는 않겠지만, 새로운 숫자는 Zygote에서 분기된 이후로 앱의 Java 힙에 할당된 모든 물리적 메모리 페이지 수를 나타냅니다. 따라서 이 숫자는 앱이 실제로 사용 중인 물리적 메모리의 양을 정확하게 표시합니다.

참고: 현재, Memory Profiler는 앱에서 실제로 프로파일링 도구에 속한 일부 가양성 네이티브 메모리 사용량도 보여줍니다. 10만 개까지의 객체를 위해 최대 10MB의 메모리가 추가됩니다. 이러한 도구의 향후 버전에서는 이들 숫자가 데이터에서 필터링을 통해 걸러질 것입니다.

메모리 할당 보기

메모리 할당은 메모리에 있는 각각의 객체가 할당된 방법을 보여줍니다. 특히, Memory Profiler는 객체 할당에 대해 다음 정보를 보여줄 수 있습니다.

기기에서 Android 8.0 이상을 실행 중인 경우 다음과 같이 언제든 객체 할당을 볼 수 있습니다. 그냥 타임라인에서 클릭한 채로 드래그하여 할당을 보고 싶은 영역을 선택하면 됩니다(동영상 1 참조). Android 8.0 이상에는 앱의 할당을 계속 추적하는 온디바이스 프로파일링 도구가 포함되어 있으므로 기록 세션을 시작할 필요가 없습니다.

동영상 1. Android 8.0 이상을 사용할 경우 기존 타임라인 영역을 선택하면 객체 할당을 볼 수 있음

기기에서 Android 7.1 또는 이전 버전을 실행 중인 경우에는 Memory Profiler 툴바에서 Record memory allocations 을 클릭하세요. Android Monitor는 기록하는 동안 앱에서 발생하는 모든 할당을 추적합니다. 다 마쳤으면 Stop recording (같은 버튼. 동영상 2 참조)을 클릭하여 할당을 볼 수 있습니다.

동영상 2. Android 7.1 또는 이전 버전을 사용할 경우에는 메모리 할당을 명시적으로 기록해야 함

타임라인의 한 영역을 선택하거나 Android 7.1 또는 이전 버전을 실행 중인 기기로 기록 세션을 마치면 타임라인 아래에 할당된 객체의 목록이 나타나는데, 객체가 클래스 이름별로 분류되고 힙 수를 기준으로 정렬되어 표시됩니다.

참고: Android 7.1 및 이전 버전에서는 최대 65,535개의 할당을 기록할 수 있습니다. 기록 세션이 이 제한을 초과하는 경우 최근 65,535개의 할당만 기록에 저장됩니다. (Android 8.0 이상에서는 실질적 제한이 없습니다.)

할당 기록을 검사하려면 다음 단계를 따르세요.

  1. 목록을 살펴보며 비정상적으로 힙 개수가 많고 누수가 발생할 수 있는 객체를 찾습니다. Class Name 열 헤더를 클릭하여 사전순으로 정렬하면 알려진 클래스를 쉽게 찾을 수 있습니다. 그런 다음, 클래스 이름을 클릭합니다. 오른쪽에 나타나는 Instance View 창에는 그림 3.1과 같이 해당 클래스의 각 인스턴스가 표시됩니다.
  2. Instance View 창에서 인스턴스를 클릭합니다. 그러면 아래에 Call Stack 탭이 나타나면서 그 인스턴스가 할당된 위치와 정확히 어떤 스레드에 할당되었는지 표시됩니다.
  3. Call Stack 탭에서 아무 라인이나 클릭하면 편집기에서 해당 코드로 이동할 수 있습니다.

그림 3. 할당된 각 객체에 대한 세부 정보가 오른쪽의 Instance View에 나타남

기본적으로, 왼쪽에 있는 할당 목록은 클래스 이름을 기준으로 정렬됩니다. 목록 맨 위에서 오른쪽에 있는 드롭다운을 사용하여 다음 정렬 방법 사이에서 전환할 수 있습니다.

힙 덤프 캡처

힙 덤프는 앱에서 어떤 객체가 힙 덤프를 캡처하는 시점에 메모리를 사용하는 중인지 보여줍니다. 특히 장시간의 사용자 세션 후, 힙 덤프는 메모리에 더 이상 남아 있으면 안 된다고 생각했는데 여전히 메모리에 있는 객체를 보여줌으로써 메모리 누수를 식별하는 데 도움이 될 수 있습니다. 힙 덤프를 캡처하고 나면 다음 내용을 볼 수 있습니다.

그림 4. 힙 덤프 보기

힙 덤프를 캡처하려면 Memory Profiler 툴바에서 Dump Java heap 을 클릭하세요. 힙을 덤프하는 동안 Java 메모리의 양이 일시적으로 증가할 수 있습니다. 힙 덤프가 앱과 동일한 프로세스에서 발생하고 데이터를 수집하려면 일부 메모리가 필요하므로 이는 정상적인 현상입니다.

그림 4와 같이, 힙 덤프가 메모리 타임라인 아래에 나타나 힙에 있는 모든 클래스 유형을 보여줍니다.

참고: 덤프가 생성되는 시점에 대해 더 정확하게 확인해야 할 경우에는 dumpHprofData()를 호출하여 앱 코드의 중요한 지점에서 힙 덤프를 생성할 수 있습니다.

힙을 검사하려면 다음 단계를 따르세요.

  1. 목록을 살펴보며 비정상적으로 힙 개수가 많고 누수가 발생할 수 있는 객체를 찾습니다. Class Name 열 헤더를 클릭하여 사전순으로 정렬하면 알려진 클래스를 쉽게 찾을 수 있습니다. 그런 다음, 클래스 이름을 클릭합니다. 오른쪽에 나타나는 Instance View 창에는 그림 5.1과 같이 해당 클래스의 각 인스턴스가 표시됩니다.
  2. Instance View 창에서 인스턴스를 클릭합니다. 아래에 나타나는 References 탭에 그 객체에 대한 모든 참조가 표시됩니다.

    또는 인스턴스 이름 옆의 화살표를 클릭하여 인스턴스의 모든 필드를 확인한 다음에 필드 이름을 클릭하여 모든 참조를 확인합니다. 필드에 대한 인스턴스 세부 정보를 보고 싶으면 필드에서 마우스 오른쪽 버튼을 클릭하고 Go to Instance를 선택합니다.

  3. References 탭에서 메모리 누수를 일으킬 수 있는 참조를 식별하는 경우 그 참조를 마우스 오른쪽 버튼으로 클릭하고 Go to Instance를 선택합니다. 그러면 힙 덤프에서 해당 인스턴스가 선택되고 자체 인스턴스 데이터를 보여줍니다.

기본적으로, 힙 덤프는 각각의 할당된 객체에 대한 스택 추적을 보여주지는 않습니다. 스택 추적을 가져오려면 메모리 할당 기록을 시작한 후에 Dump Java heap을 클릭해야 합니다. 그러면 Instance View에서 인스턴스를 선택하고 그림 5와 같이 References 탭과 나란히 Call Stack 탭을 볼 수 있습니다. 하지만 기록 할당을 시작하기 전에 일부 객체가 할당되었을 가능성이 있으므로 해당 객체에 대해서는 호출 스택을 사용할 수 없습니다. 호출 스택을 포함하고 있는 인스턴스는 아이콘 에 '스택' 배지와 함께 표시됩니다. (하지만 아쉽게도, 스택 추적에서는 할당 기록을 수행해야 하므로 현재 Android 8.0에서는 힙 덤프에 대한 스택 추적을 볼 수 없습니다.)

힙 덤프에서 다음과 같은 원인으로 인한 메모리 누수가 있는지 살펴보세요.

그림 5. 힙 덤프 캡처에 필요한 기간이 타임라인에 표시되어 있음

클래스의 목록에서 다음 정보를 확인할 수 있습니다.

클래스 목록의 맨 위에서 왼쪽 드롭다운 목록을 사용하여 다음 힙 덤프 간을 전환할 수 있습니다.

기본적으로, 힙에 있는 객체의 목록은 클래스 이름을 기준으로 정렬됩니다. 다른 드롭다운을 사용하여 다음과 같은 정렬 방법 사이에서 전환할 수 있습니다.

기본적으로, 이 목록은 Retained Size 열을 기준으로 정렬됩니다. 열 헤더 중 어느 것이든 클릭하면 목록 정렬 방식을 변경할 수 있습니다.

Instance View에서 각 인스턴스에는 다음이 포함됩니다.

힙 덤프를 HPROF로 저장

힙 덤프를 캡처한 후 프로파일러가 실행 중인 동안에만 Memory Profiler에서 데이터를 볼 수 있습니다. 프로파일링 세션을 종료하면 힙 덤프를 잃게 됩니다. 따라서 이후에 리뷰할 목적으로 힙 덤프를 저장하고 싶으면 타임라인 아래의 툴바에서 Export heap dump as HPROF file 을 클릭하여 HPROF 파일로 힙 덤프를 내보내세요. 이때 나타나는 대화상자에서 .hprof 접미사를 붙여 파일을 저장해야 합니다.

그러면 Android Studio에서 빈 편집기 창으로 파일을 드래그하거나 파일 탭 표시줄에 드롭하여 다시 열 수 있습니다.

jhat 등의 다른 HPROF 분석기를 사용하려면 HPROF 파일을 Android 형식에서 Java SE HPROF 형식으로 변환해야 합니다.

android_sdk/platform-tools/ 디렉토리에 제공되는 hprof-conv 도구로 변환할 수 있습니다. 원본 HPROF 파일과 변환된 HPROF 파일을 쓸 위치를 나타내는 두 가지 인수를 포함한 hprof-conv 명령어를 실행합니다. 예:

hprof-conv heap-original.hprof heap-converted.hprof

메모리 프로파일링 기술

Memory Profiler를 사용하는 동안 앱 코드에 스트레스를 가해 강제로 메모리 누수를 일으켜보세요. 앱에서 메모리 누수를 유발하는 한 가지 방법은 힙을 검사하기 전에 잠깐 동안 앱이 실행되도록 두는 것입니다. 그러면 조금씩 누수되다가 힙의 할당 상한에 이르게 됩니다. 하지만 누수가 적을수록 앱을 더 오래 실행해야 이러한 현상을 볼 수 있습니다.

다음 중 한 가지 방법으로 메모리 누수를 트리거할 수도 있습니다.

팁: monkeyrunner 테스트 프레임워크를 사용해 위 절차를 수행할 수도 있습니다.

This site uses cookies to store your preferences for site-specific language and display options.

Get the latest Android developer news and tips that will help you find success on Google Play.

* Required Fields

Hooray!

WeChat에서 Google Developers 팔로우하기

Browse this site in ?

You requested a page in , but your language preference for this site is .

Would you like to change your language preference and browse this site in ? If you want to change your language preference later, use the language menu at the bottom of each page.

This class requires API level or higher

This doc is hidden because your selected API level for the documentation is . You can change the documentation API level with the selector above the left navigation.

For more information about specifying the API level your app requires, read Supporting Different Platform Versions.

Take a short survey?
Help us improve the Android developer experience. (Dec 2017 Android Platform & Tools Survey)