android ART GC Log

Android Memory ART

ART의 목적

안드로이드 상 시스템이나 어플리케이션에 의해 관리 되는 Android Runtime을 대표 하는 말로써, 오직 안드로이드 프로젝트를 위해서만 만들어졌다. ART나 달빅의 경우는 Dex bytecode 러닝에 적합하게 만들어 졌다.

Ahead-of-tiem (AOT) compilation

인스톨 및 작동 시간을 빠르게 하기 위해 있는 것으로 최초 apk를 install하게 되면 dex2oat라는 device 내부에 있는 tool을 이용해서 작동가능한 상태로 만들어 준다.

Improved garbage collection

  • GC를 한번에 처리하게 만든다
  • GC pause동안 병행 프로세스 처리를 한다
  • 작은 객체(만들어진지 얼마 안된 객체, short live 객체)들을 수집한다
  • GC 처리를 적절하게 병행 처리 함으로써 GC_FOR_ALLOC이 최대한 발생 하지 않게 한다
  • 백그라운드 메모리 사용이나, 메모리 파편화를 줄여 준다 (Compacting GC)

Development and debugging improvements

아래와 같은 오류 정보들을 ART가 제공하게 된다.

java.lang.NullPointerException: Attempt to write to field 'int
android.accessibilityservice.AccessibilityServiceInfo.flags' on a null object
reference

ART 로그 설명

Art(Android Runtime)는 명시적으로 요청된 Garbage Collection에 대해서만 결과를 출력함

출력 형태는 다음과 같음

I/art: <GC_Reason> <GC_Name> <Objects_freed>(<Size_freed>) AllocSpace Objects, <Large_objects_freed>(<Large_object_size_freed>) <Heap_stats> LOS objects, <Pause_time(s)>

실제 사용은 다음과 같이 출력됨

I art : Explicit concurrent mark sweep GC freed 64(14KB) AllocSpace objects, 2(72KB) LOS objects, 24% free, 4MB/5MB, paused 448us total 20.082ms:

조금더 자세하게 나누어 보면 다음과 같음

Type 대상 설명
GC_Reason Explicit - Concurrent : 앱스레드 중단 않는 GC (백그라운드 실행)
- Alloc : 힙이 이미 가득 차서 더 이상 요청받은 메모리 할당을 할 수없어서, GC를 우선 실행 시킴
-Explicit : 앱이 명시적인 GC를 요청함. gc() 호출
- NativeAlloc : Bitmap또는 Renderscript 할당과 같은 Native 메모리 할당을 위해서 실행 되는 GC (허니비를 기점으로 Bitmap은 힙으로 위치를 변경하였다)
- CollectorTransition : RAM 사양이 낮은 기기에서 앱의 프로세스 상태 일시 중지 및 인식 할 수없는 상태로 변경 할때 변환이 발생함(메모리 공간을 범프 포인터 공간으로 복사하는 작업임)(Eden 영역에서 -> Survivor 영역으로의 전환 과정으로 보임)
- HomogeneousSpaceCompact : 사용가능한 공간(메모리로 보임)의 압축 기법으로 백그라운드 상태에서 RAM사용량 감소와 힙 조각 모음을 위해 처리 하는 것으로 보임
- HeapTrim : 힙트림을 마주칠 때까지 수집이 차단
- DisableMovingGc : 힙압축이 이루어지는 동안 GetPrimitiveArrayCritical이 사용 됨으로써 힙의 수집기 이동을 제한 시킴
GC_Name concurrent mark sweep - Concurrent mark sweep (CMS) : 이미지 공간 이외의 모든 공간을 회수하고 수집하는 완전한 힙 수집기
- Concurrent partial mark sweep : 이미지 및 zygote (app_process, 요청을 리스닝하고 요청 받은 클래스를 포크한다.)공간 이외의 공간을 전부 수집하는 수집기
- Concurrent sticky mark sweep : 마지막 GC이후로 할당된 객체만 회수 하는 세대별 수집기. 수집이 빠르고 일시 중지도 잘 안일어 남으로 자주 사용됨
-Marksweep + semispace : 공간 압축이나 힙전환시 사용되는 복사 GC
Objects_freed freed 64 회수한 객체의 수(작은규모)
Size_freed (14KB) AllocSpace objects, 2 GC를 통해서 회수한 바이트의 수
Large_objects_freed 2 회수한 객체의 수(큰 규모)
Large_object_size_freed (72KB) 회수한 객체의 크기
Heap_stats 24% free, 4MB/5MB, 회수한 비율로 (라이브 객체수)/(총 힙 크기), 예를 들자면 4MB가 살아있는 개체이고 5MB가 전체 힙의 크기이다. 약 24% 1MB 정도가 비어 있는 상황이라고 보면 된다. 이 값으 전체 적으로 증가만 하고 있다면 메모리 릭이라고 생각해 봐야한다
Pause Times paused 448us total 20.082ms 공식 문서상에는 일시 중지 횟수로 나와있으나 단위를 보면 일시 중지 시간이 맞는거 같다. 객체 수집시 나타나는 일시 중지 시간 평균 및 sum이 이 pause times으로 생각된다.

Android Memory Kill 순서

시스템 관련 서비스 memory status
Cached 현재 작동 되고 있지 않고 Background에 캐쉬 되어 있는 서비스들 lmk(Low memory killer) threshold
Previous 현재 작동 중인 서비스 직전에 사용된 서비스 critical
Home Home 기능이라고 하는데 내용상 바탕화면의 Wall paper 정도로 보임 critical
Service 클라우드 서비스, 싱크 서비스 등 백그라운드 서비스 critical
Perceptible 조회기능, 오디오, 키보드 등 듣고 입력하는 기능 들로 보임 critical
Foreground 현재 떠있는 서비스 critical
Persistent 전화 본연의 기능 및 통신 프로톨(와이파이, 블루투스 등) Crash ()
System system_server Crash (reboot)
Native init, kswapd,netd, logd, adbd 등 native bin(exec) 프로세스 Crash (reboot)

맨 위에서 부터 순차적으로 프로세스가 kill되기 시작함

lmk : low memory killer

kswapd : kernel swap daemon

 

Android Memory Debug Tool

Profiler 만 사용하면 다른 툴을 쓸 필요가 없는 것으로 보인다. 단, malloc 같은 경우는 native 영역에 대한 내용을 볼 수 있는 유일한 방법으로 현재까지는 보임으로 native leak이 발생하면 쓸수 밖에 없지 않나 한다.

 

Android RAM의 종류

RAM 사용량 Command

adb shell dumpsys meminfo <package_name|pid> [-d]

해당 명령어는 adb connect 가 되어있다는 전제이다

  • -d 옵션 의미 : Dalvick 및 ART 메모리 사용량에 대한 정보가 상세히 출력된다
  • 기본적을 KB단위로 나열된다.

 

개인(클림 및 더티) RAM

RAM은 특정 APP에서만 사용중인 메모리로써, 해당 메모리의 양은 특정 APP의 서비스가 프로세스 킬되었을 때 온전히 Free RAM으로 되돌려 받을 수 있는 양이다. 이중에 개인 더티 RAM은 Android 스왑을 사용하지 않기 때문에 가장 중요한 대상이 된다. 메모리 Leak을 해결 해야 하는 이유도 이부분에 있다. 개발자가 지정하는 모든 Dalvik 및 Native 힙 메모리는 더티 RAM으로 처리된다. Zygote를 사용하는 공유 RAM도 있게 되는데 이부분은 공유 더티 Ram으로 불린다.

PSS(Propotional Set Size)

PSS는 하나의 프로세스만을 바라보는 사이징 방식이 아니라, 공유되는 모든 페이지에 대한 RAM까지 포함한 계산 방식이다. 예를 들자면 프로세스 2개가 2메가를 공유하는 프로세스를 접근 하고 있다면, 1MB씩 PSS 사이즈를 분배 받게 된다. 그외 개인 더티 RAM 사이즈는 직접적으로 PSS에 추가 된다.

정리하자면 다음과 같다.

  • PSS Size = 프로세스1 개인 더티 RAM + 프로세스 2 개인 더티 RAM + 프로세스 3 공유 RAM 절반

PSS외에 2가지 종류가 더 있다

RSS : Resident Set Size = Private 더티 RAM + Shared RAM 전체

USS : Unique Set Size = RSS - shared RAM 전체 = Private Dirty RAM만 대상으로 함

 

아래는 com.example.app의 메모리 사용량을 나타낸다.

Applications Memory Usage (kB):
Uptime: 2452592 Realtime: 2452592

** MEMINFO in pid 4739 [com.example.app] **
                   Pss  Private  Private  Swapped     Heap     Heap     Heap
                 Total    Dirty    Clean    Dirty     Size    Alloc     Free
                ------   ------   ------   ------   ------   ------   ------
  Native Heap     6691     6648        0        0    16384     8945     7438
  Dalvik Heap     1664     1512        0        0     7045     5418     1627
 Dalvik Other      304      304        0        0
        Stack      392      392        0        0
       Ashmem      128      128        0        0
    Other dev        4        0        4        0
     .so mmap     8218      260     1640        0
    .apk mmap      305        0       24        0
    .ttf mmap       93        0        0        0
    .dex mmap     2124        0     1776        0
    .oat mmap     2144        0       64        0
    .art mmap     2214     1988        4        0
   Other mmap      296        4        0        0
      Unknown     2072     2072        0        0
        TOTAL    26649    13308     3512        0    23429    14363     9065

 Dalvik Details
        .Heap      964      964        0        0
          .GC      188      188        0        0
      .Zygote      424      272        0        0
   .NonMoving      276      276        0        0
 .IndirectRef      116      116        0        0

 Objects
               Views:        9         ViewRootImpl:        0
         AppContexts:        3           Activities:        1
              Assets:        3        AssetManagers:        3
       Local Binders:       13        Proxy Binders:       15
       Parcel memory:        5         Parcel count:       20
    Death Recipients:        0      OpenSSL Sockets:        0

 SQL
         MEMORY_USED:        0
  PAGECACHE_OVERFLOW:        0          MALLOC_SIZE:        0

Dalvik Heap

자바 머신인 달빅의 heap 모델은 External과 Dalvik heap으로 나뉘게 되는데 이중에 Dalvik Heap은

  • Java객체 인스턴스 메모리 할당
  • Zygote 할당 영역 포함

을 하게 된다.

그러나 java의 메모리 범위 밖을 보게 된다면 Native Heap이 나타나게 되는데, 이부분은 OS 영역의 메모리를 사용하는 범위로 주로 NDK로 개발된 경우 C++, C로 개발된 로우레벨 라이브러리를 사용하는 경우가 된다.

  • Bitmap의 경우 가장 대표적인 Native Heap 저장 대상이다.

Java는 Bitmap data를 Native Heap 부분으로 Pointing하는 역할만 한다.

Dalvik Other

문서상으로는 정확히 명시 되어 있지는 않는데 참고 문항으로 추리 해보면 다음과 같이 생각하면 될것 같다

  • Just in time 컴파일 기록
  • GC 기록

등 Dalvik Overhead

추측이긴 한데 ART에서 생성되는 각종 정보가 이쪽 메모리 사이즈로 쌓이는 것으로 생각된다.

 

Heap Alloc

해당 앱에 할당된 메모리 크기 인다. 이게 PSS Total보다 큰 이유는 공유 자원에 대한 값까지 같이 포함 하고 있기 때문이라고 한다.

Private Dirty

해당 앱 프로세스 내부에서만 사용되는 메모리로 타 앱 및 프로세스와 공유 되지 않는다. 프로세스가 종료 되면 이 메모리는 100% 반환 되어야 한다.

Private Clean

개발자 앱의 자체 코드임, 개발자가 만든 code자체에 대한 글이 이곳에 적제 되는 것으로 보임

so,dex mmap과 관련이 있음

.so에는 private 더티 RAM이 크게 할당 되어있는데 이는 네이티브 코드를 최종 주소 로드 할때 수정했기 때문이다.

실행 중인 코드에 대한 정보를 담는 부분으로 보임

 

.so .dex mmap

.so 네이티브 및 .dex 달빅 또는 ART를 위한 코드용으로 사용하는 RAM

.oat mmap

여러 앱이 공통적으로 사용하는 앱의 메모리 공간으로 특정 앱에 영향을 받지 않음

.Unknow

도구가 식별하기 힘든 RAM 페이지로, 주로 네이티브 할당이 주를 이룬다.

 

Dalvik Detail

.Heap : 앱의 힙의 메모리 크기 (zygote 공간 과 private 공간 포함)

.LOS : ART 대형 객체 공간 메모리

.GC : GC 계정 오버헤드 크기로 수정할 수없음

.JITCache : 실행되는 시점으로 o이 될것임

.Zygote : 공통 메모리 크기

.NonMoving : ART 비이동 공간 사용 RAM, 앱에서 사용하는 필드와 메서드 수를 줄이면 이부분이 줄어듬

.IndirectRef : ART 간접 참조 테이블, 로컬 및 전역 JNI 참조 수를 줄이면 줄일 수 있음

 

Objects

Views : 모든 View 객체의 수이다. 만약에 layout에 버튼 3개가 있고 views가 9인 상태라면, 하나의 버튼을 삭제 하면 8이 된다.

ViewRootImpl : 현재 작동중인 View의 갯수. 보이지 않는 창이라던가 연관되어있는 view와의 갯수를 확인해서 메모리 누수를 확인 할 수있다.

화면이 안떠있다면 0, 한개 View가 떠있다면 1이런식이다.

 

Activities

Activity의 갯수로써 현재 떠있는 Activity의 갯수가 된다. 한개의 큰 화면만 떠있다면 Activity는 1개이다

 

AppContexts

만약에 Activity A가 죽고 Activity B가 살아나는 시점에, A의 context가 살아있다면(Leak) 이때 AppContexts는 지속적으로 증가하는 것으로 보임

 

ProxyBinders/Parcel count/Local Binders

lyaout 상 객체를 Bind 하면서 카운트가 올라 가는 것으로 보임

728x90
반응형

'Android' 카테고리의 다른 글

AOSP system app install  (0) 2020.08.20
Android Grafika Texture Surface  (0) 2020.03.27
android memory leak 처리  (0) 2020.03.27
android graphic architecture  (0) 2020.03.27
android keyboard show on the web  (0) 2020.03.27