힙 덤프 캡처

힙 덤프를 캡처하여 캡처 시점에 앱에서 메모리를 사용 중인 객체를 확인하고 메모리 누수 또는 끊김 현상, 멈춤, 심지어 앱 비정상 종료로 이어지는 메모리 할당 동작을 식별합니다. 장기적인 사용자 세션 후에는 더 이상 메모리에 없어야 한다고 생각되는데 아직 메모리에 있는 객체를 보여주므로 힙 덤프를 가져오는 것이 특히 유용합니다.

이 페이지에서는 Android 스튜디오에서 힙 덤프를 수집하고 분석하기 위해 제공하는 도구를 설명합니다. 또는 명령줄에서 dumpsys를 사용하여 앱 메모리를 검사할 수 있고 Logcat에서 가비지 컬렉션 (GC) 이벤트를 확인할 수도 있습니다.

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

Android에서는 관리되는 메모리 환경을 제공합니다. 즉, Android에서 앱이 일부 객체를 더 이상 사용하지 않는다고 판단되면 가비지 컬렉터가 사용되지 않는 메모리를 힙에 돌려보냅니다. Android에서 사용되지 않는 메모리를 찾는 방법은 끊임없이 개선되고 있지만, 모든 Android 버전의 특정 시점에서 시스템이 코드를 일시중지해야 합니다. 대부분의 경우 일시중지를 감지할 수 없습니다. 하지만 앱이 시스템에서 수집할 수 있는 것보다 빠르게 메모리를 할당하는 경우 컬렉터가 할당을 충족할 만큼 충분한 메모리를 확보하는 동안 앱이 지연될 수 있습니다. 이로 인해 앱이 프레임을 건너뛰고 눈에 띄게 느려질 수 있습니다.

앱이 느려지지 않더라도 메모리 누수가 발생할 경우 앱이 백그라운드에 있는 동안에도 메모리를 유지할 수 있습니다. 이 동작으로 인해 불필요한 가비지 컬렉션 이벤트가 강제로 실행되어 시스템의 나머지 메모리 성능이 저하될 수 있습니다. 결국 시스템에서 메모리를 확보하기 위해 앱 프로세스를 강제 종료해야 합니다. 그러면 사용자가 앱으로 돌아올 때 앱 프로세스를 완전히 다시 시작해야 합니다.

앱의 메모리 사용을 줄일 수 있는 프로그래밍 방법에 관한 정보는 앱 메모리 관리를 참고하세요.

힙 덤프 개요

힙 덤프를 캡처하려면 메모리 사용량 분석 (힙 덤프) 작업을 선택하여(프로파일러: 'app'을 디버깅 가능으로 실행 (전체 데이터) 사용) 힙 덤프를 캡처합니다. 힙을 덤프하는 동안 Java 메모리의 양이 일시적으로 증가할 수도 있습니다. 자바 메모리의 양이 증가하는 것은 힙 덤프가 앱과 동일한 프로세스에서 발생하고 데이터를 수집하기 위해 메모리가 필요하므로 정상적인 현상입니다. 힙 덤프를 캡처하면 다음이 표시됩니다.

Android 스튜디오 프로파일러의 힙 덤프 뷰.

클래스 목록에는 다음 정보가 표시됩니다.

  • Allocations: 힙의 할당 수.
  • Native Size: 이 객체 유형에서 사용하는 총 네이티브 메모리의 양 (바이트). Android에서는 Bitmap 등 일부 프레임워크 클래스에 네이티브 메모리를 사용하므로 Java에서 할당된 일부 객체의 경우 여기에 메모리가 표시됩니다.

  • Shallow Size: 이 객체 유형에서 사용하는 총 Java 메모리의 양 (바이트)

  • Retained Size: 이 클래스의 모든 인스턴스로 인해 유지되는 총 메모리 크기 (바이트).

힙 메뉴를 사용하여 특정 힙으로 필터링합니다.

  • 앱 힙 (기본값): 앱에서 메모리를 할당하는 기본 힙입니다.
  • 이미지 힙: 부팅하는 동안 미리 로드된 클래스가 포함된 시스템 부팅 이미지입니다. 여기서는 할당이 이동하거나 사라지지 않습니다.
  • Zygote heap: Android 시스템에서 앱 프로세스가 포크되는 COW(기록 중 복사) 힙.

정렬 드롭다운을 사용하여 할당을 정렬할 방법을 선택합니다.

  • Arrange by class (기본값): 클래스 이름을 기반으로 모든 할당을 그룹화합니다.
  • Arrange by package: 패키지 이름을 기반으로 모든 할당을 분류합니다.

수업 드롭다운을 사용하여 수업 그룹을 필터링합니다.

  • 모든 클래스 (기본값): 라이브러리 및 종속 항목의 클래스를 포함한 모든 클래스를 표시합니다.
  • 활동/프래그먼트 누수 표시: 메모리 누수를 일으키는 클래스를 표시합니다.
  • 프로젝트 클래스 표시: 프로젝트에서 정의한 클래스만 표시합니다.

클래스 이름을 클릭하여 인스턴스 창을 엽니다. 나열된 각 인스턴스에는 다음이 포함됩니다.

  • Depth: 임의의 GC 루트에서 선택된 인스턴스까지 가장 짧은 홉 수.
  • Native Size: 네이티브 메모리에서 이 인스턴스의 크기. 이 열은 Android 7.0 이상의 경우에만 표시됩니다.
  • Shallow Size: 자바 메모리에서 이 인스턴스의 크기
  • Retained Size: 도미네이터 트리에 따라 이 인스턴스가 지배하는 메모리의 크기

인스턴스를 클릭하여 필드참조를 비롯한 인스턴스 세부정보를 표시합니다. 일반적인 필드 및 참조 유형은 Java의 구조화된 유형 , 배열 , 기본 데이터 유형 입니다. 필드 또는 참조를 마우스 오른쪽 버튼으로 클릭하여 소스 코드의 연결된 인스턴스 또는 줄로 이동합니다.

  • 필드: 이 인스턴스의 모든 필드를 표시합니다.
  • 참조: 인스턴스 탭에서 강조 표시된 객체에 대한 모든 참조를 보여줍니다.
힙 덤프 도구 창의 인스턴스, 필드, 참조

메모리 누수 찾기

메모리 누수와 연결될 수 있는 클래스를 빠르게 필터링하려면 클래스 드롭다운을 열고 활동/프래그먼트 누수 표시를 선택합니다. Android 스튜디오는 앱의 ActivityFragment 인스턴스에서 메모리 누수가 의심되는 클래스를 표시합니다.

메모리 누수를 더 수동으로 찾으려면 클래스 및 인스턴스 목록을 탐색하여 보관된 크기가 큰 객체를 찾으세요. 다음과 같은 이유로 인해 발생한 메모리 누수가 있는지 확인하세요.

  • 호스팅된 Compose 컴포지션 그래프 (예: ComposeView 및 하위 컴포저블)를 누수시킬 수 있는 Activity 또는 Context에 대한 수명이 긴 참조
  • MutableState, 상태 홀더 또는 Context를 캡처하는 람다에서 Jetpack Compose 상태 객체가 누수됩니다.
  • DisposableEffectonDispose 블록에서 리스너나 관찰자를 정리하는 것을 잊습니다.
  • Runnable과 같이 Activity 인스턴스를 보유할 수 있는 비정적 내부 클래스
  • 필요 이상으로 오랫동안 객체를 보유하는 캐시

잠재적인 메모리 누수를 발견하면 인스턴스 세부정보필드참조 탭을 사용하여 관심 있는 인스턴스 또는 소스 코드 줄로 이동합니다.

테스트를 위해 메모리 누수 트리거

메모리 사용량을 분석하려면 앱 코드에 스트레스를 주어 강제로 메모리 누수를 유발해야 합니다. 앱에서 메모리 누수를 유발하는 한 가지 방법은 힙을 검사하기 전에 잠시 동안 앱이 실행되도록 하는 것입니다. 메모리가 힙의 할당 상한까지 서서히 누출될 수 있습니다. 하지만 누출이 적을수록 더 오랫동안 앱을 실행해야 누출을 확인할 수 있습니다.

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

  • 기기가 다양한 활동 상태에 있는 동안 기기를 세로 모드에서 가로 모드로 회전했다가 다시 되돌리기를 여러 번 반복합니다. 비동기 작업이나 상태 홀더 내에서 앱이 Activity 또는 Context에 대한 참조를 유지하는 경우 기기를 회전하면 앱에서 Activity (따라서 호스팅된 Compose UI 트리 및 연결된 상태 트리)가 누출되는 경우가 많습니다.
  • 다양한 활동 상태에 있는 동안 앱과 다른 앱 간을 전환합니다. 예를 들어 홈 화면으로 이동한 다음 앱으로 돌아갑니다.

힙 덤프 녹화 내보내기 및 가져오기

프로파일러의 이전 녹음 파일 탭에서 힙 덤프 파일을 내보내고 가져올 수 있습니다. Android 스튜디오는 녹화 내용을 .hprof 파일로 저장합니다.

또는 jhat과 같은 다른 .hprof 파일 분석기를 사용하려면 .hprof 파일을 Android 형식에서 Java SE .hprof 파일 형식으로 변환해야 합니다. 파일 형식을 변환하려면 {android_sdk}/platform-tools/ 디렉터리에 제공된 hprof-conv 도구를 사용하세요. 두 개의 인수, 즉 원본 .hprof 파일 이름과 변환된 .hprof 파일을 작성할 위치(새 .hprof 파일 이름 포함)를 사용하여 hprof-conv 명령어를 실행하세요. 예를 들면 다음과 같습니다.

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

추가 리소스