힙 덤프를 캡처하여 캡처 시점에 앱에서 메모리를 사용 중인 객체를 확인하고 메모리 누수 또는 끊김, 정지, 심지어 앱 비정상 종료로 이어지는 메모리 할당 동작을 식별합니다. 더 이상 메모리에 없어야 하는데 아직 메모리에 있는 객체를 보여줄 수 있는 장기적인 사용자 세션 후 힙 덤프를 가져오는 것이 특히 유용합니다.
이 페이지에서는 Android 스튜디오에서 힙 덤프를 수집하고 분석하기 위해 제공하는 도구를 설명합니다. 또는
명령줄에서 dumpsys를 사용하여 앱 메모리를 검사할 수 있고
Logcat에서 가비지 컬렉션 (GC) 이벤트를 확인할 수도 있습니다.
앱 메모리를 프로파일링해야 하는 이유
Android에서는 관리되는 메모리 환경을 제공합니다. 즉, Android에서 앱에서 일부 객체를 더 이상 사용하지 않는다고 판단되면 가비지 컬렉터가 사용되지 않는 메모리를 힙에 돌려보냅니다. Android에서 사용되지 않는 메모리를 찾는 방법은 지속적으로 개선되고 있지만 모든 Android 버전에서 시스템은 잠시 코드를 일시중지해야 합니다. 대부분의 경우 일시중지는 감지할 수 없습니다. 하지만, 시스템에서 메모리를 수집할 수 있는 것보다 빠르게 앱에서 메모리를 할당하는 경우 컬렉터가 할당하기에 충분한 메모리를 확보하는 동안 앱이 지연될 수 있습니다. 이로 인해 앱이 프레임을 건너뛰고 눈에 띄게 느려질 수 있습니다.
앱이 느려지지 않더라도 메모리 누수가 발생할 경우 앱이 백그라운드에 있는 동안에도 메모리를 유지할 수 있습니다. 이 동작으로 인해 불필요한 가비지 컬렉션 이벤트가 강제로 실행되어 시스템의 나머지 메모리 성능이 저하될 수 있습니다. 결국 시스템에서 메모리를 확보하기 위해 앱 프로세스를 강제 종료해야 합니다. 그러면 사용자가 앱으로 돌아올 때 앱 프로세스를 완전히 다시 시작해야 합니다.
앱의 메모리 사용을 줄일 수 있는 프로그래밍 방법에 관한 정보는 앱 메모리 관리를 참고하세요.
힙 덤프 개요
힙 덤프를 캡처하려면 Analyze Memory Usage (Heap Dump) 작업을 선택합니다 (Profiler: run 'app' as debuggable (complete data) 사용). 힙을 덤프하는 동안 자바 메모리의 양이 일시적으로 증가할 수도 있습니다. 자바 메모리의 양이 증가하는 것은 힙 덤프가 앱과 동일한 프로세스에서 발생하고 데이터를 수집하기 위해 메모리가 필요하므로 정상적인 현상입니다. 힙 덤프를 캡처한 후 다음이 표시됩니다.
클래스 목록에는 다음 정보가 표시됩니다.
- 할당: 힙의 할당 수.
네이티브 크기: 이 객체 유형에서 사용하는 총 네이티브 메모리의 양 (바이트). Android에서는 Android uses native memory for some framework classes, such as
Bitmap등 일부 프레임워크 클래스에 네이티브 메모리를 사용하므로 자바에서 할당된 일부 객체의 경우 여기에 메모리가 표시됩니다.Shallow Size: 이 객체 유형에서 사용하는 총 자바 메모리의 양 (바이트).
유지된 크기: 이 클래스의 모든 인스턴스로 인해 유지되는 총 메모리 크기 (바이트).
힙 메뉴를 사용하여 특정 힙으로 필터링합니다.
- App heap (default): 앱에서 메모리를 할당하는 기본 힙.
- 이미지 힙: 부팅하는 동안 미리 로드된 클래스가 포함된 시스템 부팅 이미지. 여기서는 할당이 결코 이동하거나 사라지지 않습니다.
- Zygote heap: Android 시스템에서 앱 프로세스가 포크되는 COW(기록 중 복사) 힙.
정렬 드롭다운을 사용하여 할당을 정렬할 방법을 선택합니다.
- 클래스별 정렬 (기본값): 클래스 이름을 기반으로 모든 할당을 분류합니다.
- Arrange by package: 패키지 이름을 기반으로 모든 할당을 분류합니다.
클래스 드롭다운을 사용하여 클래스 그룹으로 필터링합니다.
- 모든 클래스 (기본값): 라이브러리 및 종속 항목의 클래스를 포함한 모든 클래스를 표시합니다.
- Show activity/fragment leaks: 메모리 누수를 일으키는 클래스를 표시합니다.
- Show project classes: 프로젝트에서 정의한 클래스만 표시합니다.
클래스 이름을 클릭하여 Instance 창을 엽니다. 나열된 각 인스턴스에는 다음이 포함됩니다.
- 깊이: 임의의 GC 루트에서 선택된 인스턴스까지 가장 짧은 홉 수.
- Native Size: 네이티브 메모리에서 이 인스턴스의 크기. 이 열은 Android 7.0 이상에서만 표시됩니다.
- Shallow Size: 자바 메모리에서 이 인스턴스의 크기
- Retained Size: 도미네이터 트리에 따라 이 인스턴스가 지배하는 메모리의 크기.
인스턴스를 클릭하여 Instance Details를 표시합니다(여기에는 Fields
및 References 포함). 일반적인 필드 및 참조 유형은 자바의 구조화된 유형
,
배열
,
기본 데이터 유형
입니다. 필드 또는 참조를 마우스 오른쪽 버튼으로 클릭하여 소스 코드의 연결된 인스턴스 또는 줄로 이동합니다.
- 필드: 이 인스턴스의 모든 필드를 표시합니다.
- 참조: 인스턴스 탭에서 강조표시된 객체에 관한 모든 참조를 표시합니다.
중복 비트맵 감지
Android 스튜디오 Narwhal 4부터 힙 덤프 뷰에서 중복 비트맵을 감지할 수도 있습니다.
다음은 중복 비트맵을 찾는 방법입니다.
- Android 스튜디오에서 프로파일러 탭을 엽니다.
- Heap Dump (또는 Analyze Memory Usage)를 클릭하고 레코드를 클릭하여 앱의 현재 메모리 상태 스냅샷을 가져옵니다.
- 분석 결과에서 Android 스튜디오에서 중복 비트맵이 여러 번 저장되고 있음을 나타내는 데 사용하는 노란색 경고 삼각형 ⚠️을 검색합니다.
- 또는 프로파일러 헤더로 이동하여 Filter by: 를 선택하고 Duplicate Bitmaps 설정을 선택합니다.
- 플래그가 지정된 항목을 클릭하여 Bitmap Preview 창을 열면 정확히 어떤 이미지가 반복되는지 확인할 수 있습니다.
- 이 시각적 확인을 사용하여 코드에서 중복 로드 로직을 추적하고 더 나은 캐싱 전략을 구현합니다.
메모리 누수 찾기
메모리 누수와 연결될 수 있는 클래스로 빠르게 필터링하려면 클래스 드롭다운을 열고 Show activity/fragment leaks 를 선택합니다. Android 스튜디오는 앱의 Activity 및 Fragment 인스턴스에서 메모리 누수를 나타낸다고 생각되는 클래스를 표시합니다.
메모리 누수를 더 수동으로 찾으려면 클래스 및 인스턴스 목록을 탐색하여 Retained Size 가 큰 객체를 찾습니다. 다음과 같은 이유로 인해 발생한 메모리 누수가 있는지 확인하세요.
- 호스팅된 Compose
컴포지션 그래프 (예:
ComposeView및 하위 컴포저블)를 누출할 수 있는Activity또는Context에 대한 장기 참조 Context를 캡처하는 Jetpack Compose 상태 객체 (MutableState), 상태 홀더 또는 람다 누출-
DisposableEffect의onDispose블록에서 리스너 또는 관찰자를 정리하는 것을 잊음 - `Runnable`과 같이 `Activity` 인스턴스를 보유할 수 있는 비정적 내부 클래스
RunnableActivity - 필요 이상으로 오랫동안 객체를 보유하는 캐시
잠재적인 메모리 누수를 발견하면 Instance Details 의 Fields 및 References 탭을 사용하여 관심 있는 인스턴스 또는 소스 코드 줄로 이동합니다.
테스트를 위한 메모리 누수 트리거
메모리 사용량을 분석하려면 앱 코드에 스트레스를 주어 강제로 메모리 누출을 유발해야 합니다. 앱에서 메모리 누수를 유발하는 한 가지 방법은 힙을 검사하기 전에 잠시 동안 앱이 실행되도록 하는 것입니다. 메모리가 힙의 할당 상한까지 서서히 누출될 수 있습니다. 하지만 누출이 작을수록 누출을 확인하기 위해 앱을 더 오래 실행해야 합니다.
다음 중 한 가지 방법으로 메모리 누수를 트리거할 수도 있습니다.
- 기기가 다양한 활동 상태에 있는 동안 기기를 세로 모드에서 가로 모드로 회전했다가 다시 되돌리기를 여러 번 반복합니다. 기기를 회전하면 앱
이 비동기 작업 또는 상태 홀더 내에서
Activity또는Context에 대한 참조를 보유하는 경우 앱에서Activity(결과적으로 호스팅된 Compose UI 트리 및 연결된 상태 트리)가 누출되는 경우가 많습니다. - 다양한 활동 상태에 있는 동안 개발자의 앱과 다른 앱 간을 전환합니다. 예를 들어 홈 화면으로 이동한 다음 개발자의 앱으로 돌아옵니다.
힙 덤프 녹화 내보내기 및 가져오기
프로파일러의 Past Recordings 탭에서 힙 덤프
파일을
내보내고 가져올 수 있습니다. Android 스튜디오는 녹화를 .hprof 파일로 저장합니다.
또는 .hprof 파일 분석기를 jhat과 같은 다른
파일 분석기로 사용하려면 .hprof 파일을 Android 형식에서 자바 SE
.hprof 파일 형식으로 변환해야 합니다. 파일 형식을 변환하려면 {android_sdk}/platform-tools/ 디렉터리에 제공된 hprof-conv 도구를 사용합니다. 두 개의 인수를 사용하여 hprof-conv 명령어를 실행합니다. 즉, 원래 .hprof 파일 이름과 새 .hprof 파일 이름을 포함하여 변환된 .hprof 파일을 쓸 위치입니다. 예:
hprof-conv heap-original.hprof heap-converted.hprof