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