메모리 프로파일러는 끊김 현상, 멈춤, 심지어 앱 비정상 종료로 이어질 수 있는 메모리 누수 및 메모리 변동을 식별하는 데 도움이 되는 Android 프로파일러의 구성요소입니다. 메모리 프로파일러는 앱의 메모리 사용 현황을 실시간 그래프로 보여주며, 메모리 프로파일러를 사용하여 힙 덤프를 캡처하고 가비지 컬렉션을 강제 실행하고 메모리 할당을 추적할 수 있습니다. Show 메모리 프로파일러를 열려면 다음 단계를 따르세요.
또는 명령줄에서 dumpsys를 사용하여 앱 메모리를 검사할 수 있고 logcat에서 GC 이벤트를 확인할 수도 있습니다. 앱 메모리를 프로파일링해야 하는 이유Android에서는 관리되는 메모리 환경을 제공합니다. 즉, 앱에서 일부 객체를 더 이상 사용하지 않는다고 판단되면 가비지 컬렉터가 사용되지 않는 메모리를 힙에 돌려보냅니다. Android에서 사용되지 않는 메모리를 찾는 방법은 끊임없이 개선되고 있지만, 모든 Android 버전의 특정 시점에서 시스템이 코드를 일시중지해야 합니다. 대부분의 경우 일시중지를 감지할 수 없습니다. 하지만, 시스템에서 메모리를 수집할 수 있는 것보다 빠르게 앱에서 메모리를 할당하는 경우 컬렉터가 할당하기에 충분한 메모리를 확보하는 동안 앱이 지연될 수 있습니다. 이로 인해 앱이 프레임을 건너뛰고 눈에 띄게 느려질 수 있습니다. 앱이 느려지지 않더라도 메모리 누수가 발생할 경우 앱이 백그라운드에 있는 동안에도 메모리를 유지할 수 있습니다. 이 동작으로 인해 불필요한 가비지 컬렉션 이벤트가 강제로 실행되어 시스템의 나머지 메모리 성능이 저하될 수 있습니다. 결국 시스템에서 메모리를 확보하기 위해 앱 프로세스를 강제 종료해야 합니다. 그러면 사용자가 앱으로 돌아올 때 앱을 완전히 다시 시작해야 합니다. 이 문제를 방지하려면 메모리 프로파일러를 사용하여 다음을 처리해야 합니다.
앱의 메모리 사용을 줄일 수 있는 프로그래밍 방법에 관한 정보는 앱 메모리 관리를 참고하세요. 메모리 프로파일러 개요메모리 프로파일러를 처음 열면 앱의 메모리 사용 현황을 보여주는 상세 타임라인이 표시되고 가비지 컬렉션을 강제 실행하고, 힙 덤프를 캡처하고, 메모리 할당을 기록할 수 있는 도구에 액세스하게 됩니다. 그림 1. 메모리 프로파일러 그림 1에 표시된 것처럼 메모리 프로파일러의 기본 뷰에는 다음 항목이 포함됩니다.
그러나 Android 7.1 이하를 실행하는 기기를 사용하는 경우 기본적으로 모든 프로파일링 데이터가 표시되지는 않습니다. 'Advanced profiling is unavailable for the selected process'라는 메시지가 표시되는 경우 다음 항목을 표시하려면 고급 프로파일링을 사용 설정해야 합니다.
Android 8.0 이상에서는 디버그 가능한 앱에 관해 고급 프로파일링이 항상 사용 설정됩니다. 메모리 계산 방법메모리 프로파일러 상단(그림 2)에는 Android 시스템에 따라 앱에서 커밋한 모든 비공개 메모리 페이지를 기반으로 한 숫자가 표시됩니다. 시스템이나 다른 앱과 공유되는 페이지는 포함되지 않습니다. 그림 2. 메모리 프로파일러 상단의 메모리 카운트 범례 메모리 카운트의 카테고리는 다음과 같습니다.
새 메모리 프로파일러는 이전 Android Monitor 도구의 메모리 카운트와는 메모리를 다르게 기록하므로 메모리 사용량이 더 많은 것으로 보일 수도 있습니다. 메모리 프로파일러는 추가 카테고리를 모니터링하므로 총 사용량이 증가하지만, 자바 힙 메모리만 중요한 경우에는 'Java' 숫자가 이전 도구의 값과 비슷해야 합니다. 'Java' 숫자는 아마도 Android Monitor에 표시된 숫자와 정확히 일치하지 않지만, 이 새로운 숫자는 Zygote에서 포크된 이후 앱의 자바 힙에 할당된 모든 실제 메모리 페이지 수를 나타냅니다. 따라서 이 숫자는 앱에서 실제로 사용 중인 실제 메모리의 양을 정확하게 나타냅니다. 메모리 할당 보기메모리 할당에는 메모리의 각 자바 객체와 JNI 참조가 할당된 방식이 표시됩니다. 구체적으로 객체 할당과 관련한 다음과 같은 정보가 메모리 프로파일러에 표시될 수 있습니다.
자바 및 Kotlin 할당을 기록하려면 Record Java / Kotlin allocations를 선택한 다음 Record를 선택합니다. 기기에서 Android 8 이상을 실행 중이면 메모리 프로파일러 UI가 진행 중인 기록을 표시하는 별도의 화면으로 전환됩니다. 기록 위에 있는 미니 타임라인과 상호작용할 수 있습니다(예: 선택 범위 변경). 기록을 완료하려면 Stop 을 선택합니다.Android 7.1 이하에서는 메모리 프로파일러가 레거시 할당 기록을 사용하여 Stop을 클릭할 때까지 타임라인에 기록을 표시합니다. 타임라인의 영역을 선택하고 나면(또는 Android 7.1 이하를 실행하는 기기를 사용하여 기록 세션을 완료한 경우) 할당된 객체의 목록이 클래스 이름별로 그룹화되고 힙 개수로 정렬되어 표시됩니다. 할당 기록을 검사하려면 다음 단계를 따르세요.
그림 3. 할당된 각 객체에 관한 세부정보가 오른쪽의 Instance View에 표시됨 할당된 객체 목록 위의 두 메뉴를 사용하여 어떤 힙을 검사할지와 데이터를 구성하는 방법을 선택할 수 있습니다. 왼쪽 메뉴에서 검사할 힙을 선택합니다.
오른쪽 메뉴에서 할당을 정렬할 방법을 선택합니다.
프로파일링하는 동안 앱 성능 개선프로파일링하는 동안 앱 성능을 개선하기 위해 메모리 프로파일러는 기본적으로 메모리 할당 샘플을 주기적으로 추출합니다. API 수준 26 이상을 실행하는 기기에서 테스트하는 경우 Allocation Tracking 드롭다운을 사용하여 이 동작을 변경할 수 있습니다. 다음과 같은 옵션을 사용할 수 있습니다.
글로벌 JNI 참조 보기JNI(Java Native Interface)는 자바 코드 및 네이티브 코드가 서로를 호출할 수 있는 프레임워크입니다. JNI 참조는 네이티브 코드에 의해 수동으로 관리되므로 네이티브 코드에서 사용하는 자바 객체가 너무 오랫동안 연결된 상태로 유지될 수 있습니다. JNI 참조가 먼저 명시적으로 삭제되지 않고 취소되면 자바 힙의 일부 객체에 도달하지 못할 수도 있습니다. 또한 글로벌 JNI 참조 한도를 소진할 수도 있습니다. 이러한 문제를 해결하려면 메모리 프로파일러의 JNI heap 뷰를 사용하여 모든 글로벌 JNI 참조를 둘러보고 자바 유형 및 네이티브 호출 스택을 기준으로 필터링하세요. 이 정보를 사용하여 글로벌 JNI 참조가 생성되고 삭제되는 시기와 위치를 알 수 있습니다. 앱이 실행되는 동안 검사하려는 타임라인 부분을 선택하고, 클래스 목록 위의 드롭다운 메뉴에서 JNI heap을 선택합니다. 그런 다음 평소와 같이 힙에 있는 객체를 검사하고 Allocation Call Stack 탭에서 객체를 더블클릭하여 그림 4와 같이 코드에서 JNI 참조가 할당되고 해제된 위치를 확인할 수 있습니다. 그림 4. 글로벌 JNI 참조 보기 앱 JNI 코드의 메모리 할당을 검사하려면 Android 8.0 이상을 실행하는 기기에 앱을 배포해야 합니다. JNI에 관한 자세한 내용은 JNI 도움말을 참고하세요. 네이티브 메모리 프로파일러Android 스튜디오 메모리 프로파일러에 Android 10을 실행하는 실제 기기에 배포된 앱의 네이티브 메모리 프로파일러가 포함됩니다. Android 11 기기 지원은 현재 Android 스튜디오 4.2 미리보기 출시에서 사용할 수 있습니다. 네이티브 메모리 프로파일러는 특정 기간 네이티브 코드에서 객체의 할당/할당 해제를 추적하고 다음 정보를 제공합니다.
Android 10 이상을 실행하는 기기에서 네이티브 할당을 기록하려면 Record native allocations를 선택한 다음 Record를 선택합니다. 기록은 Stop 을 클릭할 때까지 계속됩니다. 클릭한 후에는 메모리 프로파일러 UI가 네이티브 기록을 표시하는 별도의 화면으로 전환됩니다.Android 9 이하에서는 Record native allocations 옵션을 사용할 수 없습니다. 기본적으로 네이티브 메모리 프로파일러는 32바이트 크기의 샘플을 사용합니다. 메모리 32바이트가 할당될 때마다 메모리의 스냅샷이 만들어집니다. 샘플 크기가 작을수록 스냅샷 생성 빈도가 높아지고 메모리 사용량에 관한 보다 정확한 데이터가 생성됩니다. 샘플 크기가 클수록 데이터의 정확도가 떨어지지만 기록하는 동안 시스템의 리소스가 더 적게 소비되고 성능이 향상됩니다. 네이티브 메모리 프로파일러의 샘플 크기를 변경하려면 다음 단계를 따르세요.
힙 덤프 캡처힙 덤프는 힙 덤프를 캡처할 때 앱에서 메모리를 사용 중인 객체를 보여줍니다. 특히 장기적인 사용자 세션 후, 더 이상 메모리에 없어야 한다고 생각되는데 아직 메모리에 있는 객체를 보여주므로 메모리 누수를 식별하는 데 도움이 됩니다. 힙 덤프를 캡처한 후 다음 정보를 확인할 수 있습니다.
힙 덤프를 캡처하려면 Capture heap dump를 클릭한 다음 Record를 선택합니다. 힙을 덤프하는 동안 자바 메모리의 양이 일시적으로 증가할 수도 있습니다. 자바 메모리의 양이 증가하는 것은 힙 덤프가 앱과 동일한 프로세스에서 발생하고 데이터를 수집하기 위해 메모리가 필요하므로 정상적인 현상입니다. 프로파일러가 힙 덤프를 캡처한 후에는 메모리 프로파일러 UI가 힙 덤프를 표시하는 별도의 화면으로 전환됩니다. 그림 5. 힙 덤프 보기 덤프가 언제 생성되는지 더 정확히 알아내려면 클래스의 목록에서 다음 정보를 확인할 수 있습니다.
할당된 객체 목록 위의 두 메뉴를 사용하여 어느 힙 덤프를 검사할지와 데이터를 구성하는 방법을 선택할 수 있습니다. 왼쪽 메뉴에서 검사할 힙을 선택합니다.
오른쪽 메뉴에서 할당을 정렬할 방법을 선택합니다.
목록은 기본적으로 Retained Size 열을 기준으로 정렬됩니다. 다른 열의 값을 기준으로 정렬하려면 열의 제목을 클릭하세요. 클래스 이름을 클릭하면 오른쪽에 Instance View 창이 열립니다(그림 6 참고). 각 인스턴스에는 다음과 같은 항목이 나열됩니다.
그림 6. 힙 덤프 캡처에 필요한 기간이 타임라인에 표시되어 있음 힙을 검사하려면 다음 단계를 따르세요.
힙 덤프에서 다음과 같은 이유로 인해 발생한 메모리 누수가 있는지 확인하세요.
힙 덤프를 HPROF 파일로 저장힙 덤프를 캡처한 후에는 프로파일러가 실행되는 동안에만 메모리 프로파일러에 데이터가 표시됩니다. 프로파일링 세션을 종료하면 힙 덤프를 잃게 됩니다. 따라서 나중에 검토하기 위해 힙 덤프를 저장하려면 HPROF 파일로 내보내세요. Android 스튜디오 3.1 이하에서는 타임라인 아래 툴바 왼쪽에 Export capture to file 버튼이 있고, Android 스튜디오 3.2 이상에서는 Sessions 창의 각 Heap Dump 항목 오른쪽에 Export Heap Dump 버튼이 있습니다. Export As 대화상자가 표시되면.hprof 파일 이름 확장자를 사용하여 파일을 저장하세요.jhat과 같은 다른 HPROF 분석기를 사용하려면 HPROF 파일을 Android 형식에서 자바 SE HPROF 형식으로
변환해야 합니다.
힙 덤프 파일 가져오기HPROF( HPROF 파일을 파일 브라우저에서 편집기 창으로 드래그하여 가져올 수도 있습니다. 메모리 프로파일러에서 누수 감지메모리 프로파일러의 힙 덤프를 분석할 때 Android 스튜디오에서 앱의 필터에 표시되는 데이터 유형은 다음과 같습니다.
다음과 같은 특정 상황에서는 필터에 거짓양성이 표시됩니다.
이 기능을 사용하려면 먼저 힙 덤프를 캡처하거나 Android 스튜디오로 힙 덤프 파일을 가져옵니다. 메모리 누수가 발생할 수 있는 프래그먼트와 활동을 표시하려면 메모리 프로파일러의 힙 덤프 창에서 Activity/Fragment Leaks 체크박스를 선택합니다(그림 7 참고). 그림 7. 메모리 누수를 일으키는 힙 덤프 필터링 메모리 프로파일링 기법메모리 프로파일러를 사용하는 동안 앱 코드에 스트레스를 주어 강제로 메모리 누수를 유발해야 합니다. 앱에서 메모리 누수를 유발하는 한 가지 방법은 힙을 검사하기 전에 잠시 동안 앱이 실행되도록 하는 것입니다. 메모리가 힙의 할당 상한까지 서서히 누수될 수 있습니다. 하지만 누수가 적을수록 더 오랫동안 앱을 실행해야 누수를 확인할 수 있습니다. 다음 중 한 가지 방법으로 메모리 누수를 트리거할 수도 있습니다.
팁: monkeyrunner 테스트 프레임워크를 사용하여 위 단계를 실행할 수도 있습니다. |