Android byDreamy postedSep 03, 2012

안드로이드 어플리케이션의 메모리 사용량을 확인하는 방법

?

단축키

Prev이전 문서

Next다음 문서

ESC닫기

+ - Up Down Comment Print

How to discover memory usage of my application in Android



오랜만에 블로그에 포스트를 남기고 있습니다. 안드로이드 개발자 블로그에서 몇 가지 재미있는 글들이 올라왔는데, 그 중에 실재 안드로이드 팀의 엔지니어 한명이 안드로이드 프로세스의 메모리 사용 정보를 확인하는 방법에 관한 글을 링크한 내용이 있더군요. 개인적으로 관심이 가는 내용이기에, 해당 링크 (stackoverflow 에 답변으로 올렸더군요.)의 내용을 번역해 보았습니다. PS.그간의 근황에 관해서는 간단하게 잡담란에 이야기를 할 예정입니다.... (뭐 별거 없이 SC2 한 이야기이지요...)

리눅스와 같은 요즘 시대의 OS 상에서 한 어플리케이션이 어떻게 메모리를 사용하고 있는지를 확인하는 것은 이해하기에 어마어마하게 복잡하고 어려운 일입니다. 사실, 여러분이 확인 할 수 있는 여러 숫자들의 의미를 정학하게 파악하는 일은 거의 불가능에 가깝습니다. (다른 개발자들과 메모리 사용에 관한 여러 수치들을 놓고 이야기를 나누게 되면, 별다른 결론도 없으면서 길고 길게 이어지는 토론으로 끝날때가 많습니다.) 따라서, 우선적으로 안드로이드에서 대략 어떤식으로 메모리가 관리되는지에 관해 설명된 다음 글의 마지막 단락을 읽어 보시면 좋습니다.

(번역: http://huewu.blog.me/110081442947)

현재 안드로이드에서는 전체적인 메모리 상황을 살펴볼 기 위한 가장 최상위 API 는 ActivityManager.getMemoryInfo() 입니다. 이 메서드는 어플리케이션이 시스템이 현재 어느 정도의 메모리 여유를 갖고 있는지, 시스템 메모리 부족으로 인하여 서비스와 같은 백그라운드 프로세스 종료 등의 작업이 어느 시점에 일어날지에 관한 예측을 할 수 있도록 도와줍니다. 하지만, 순수한 자바 어플리케이션에서는 이 메서드는 사용할 필요가 별로 없습니다. 왜냐하면 자바 힙 메모리에는 제한이 걸려 있음으로(주>제가 알기로는 16메가 정도...) 하나의 어플리케이션이 시스템 전체 메모리에 부하를 주는 일을 방지하는 역할을 수행하기 때문입니다.

조금더 하위 레벨로 내려가보면, 메모리 사용에 관한 커널 레벨의 정보를 얻기위하여 Debug API 를 사용할 수 있습니다.

http://developer.android.com/intl/de/reference/android/os/Debug.html

안드로이드 2.0 이후부터는 자신이 아닌 다른 프로세스의 메모리 정보를 얻기 위한 ActivityManager.getProcessMemoryInfo 메서드가 추가되었습니다.

http://developer.android.com/reference/android/app/ActivityManager.html#getProcessMemoryInfo(int[])

결과로 반환되는 MemoryInfo 구조체에는 아래와 같은 정보가 포함되어 있습니다.

    /** The proportional set size for dalvik. */
public int dalvikPss;
/** The private dirty pages used by dalvik. */
public int dalvikPrivateDirty;
/** The shared dirty pages used by dalvik. */
public int dalvikSharedDirty;

/** The proportional set size for the native heap. */
public int nativePss;
/** The private dirty pages used by the native heap. */
public int nativePrivateDirty;
/** The shared dirty pages used by the native heap. */
public int nativeSharedDirty;

/** The proportional set size for everything else. */
public int otherPss;
/** The private dirty pages used by everything else. */
public int otherPrivateDirty;
/** The shared dirty pages used by everything else. */
public int otherSharedDirty;

하지만 도데체 "Proportional Set Size", "PrivateDirty", "SharedDirty" 이 것들은 무슨 뜻이고, 무슨 차이점이 있는 걸까요? 바로 여기서 부터 몇 가지 재미있는 이야기가 시작됩니다.

안드로이드(그리고 일반적인 리눅스)상에서 실재로는 서로 다른 프로세스가 메모리의 많은 부분을 공유해서 사용합니다. 따라서, 하나의 프로세스가 실재 얼만큼의 메모리를 사용하고 있는가는 명확하지 않습니다. 더군다나 메모리 페이지 영역을 디스크에 저장하는 경우를 추가해 생각해 보면 더더욱 명확하지 않습니다. 그러므로, 만일 여러분이 각각의 프로세스가 매핑하고 있는 실재 메모리 영역을 모두 더해보면, 아마도 여러분의 실재 RAM 크기보다 훨씬 큰 값을 얻게 될 것입니다.

PSS 는 프로세스간에 공유된 메모리를 고려하여 커널이 계산한 수치입니다. 하나의 메모리 페이지 영역에 관하여, 해당 페이지를 공유하는 프로스세의 수를 기반으로 해당 메모리 영역을 나누어 메모리 사용량을 계산합니다. 이러한 방식을 통해 (이론적으로는) 모든 프로세스들의 PSS 값을 더하면 전체 프로세스가 사용하는 총 RAM 사이즈를 알 수 있습니다. 그리고 프로세스간의 PSS 값을 비교해보면 상대적으로 어떤 프로세스가 어느정도의 메모리를 사용하는지 대략적인 상황을 확인 할 수 있습니다.

PrivateDirty 도 재미있는 수치입니다. 이 수치는 프로세스에 할당된 RAM 중에, 디스크로 저장될 수 없으며(메모리가 부족할 경우 디스크를 가상 메모리처럼 사용할 수 없음), 다른 프로세스와 공유될 수 없는 공간을 기반으로 계산됩니다. 이 수치는 해당 프로세스가 종료되었을 때 순수하게 시스템이 확보할 수 있는 메모리 공간이 어느정도 되는지를 확인하는 의미로 사용될 수 있습니다.

ADB 를 이용하여, 현재 동작중인 시스템의 메모리 사용에 관해 더 많은 정보를 확인 할 수 있습니다. 이 때 사용되는 일반적인 명령어 중 하나는 "adb shell dumpsys meminfo" 입니다. 이 명령어는 각각의 자바 프로세스가 사용중인 메모리에 관한 정보를 쏟아내는데, 위에 설명한 내용 외에도 다양한 내용이 포함되어 있습니다. 또한 여러분은 특정 프로세스의 PID 나 프로세스 이름을 이용하여 해당 프로세스의 메모리 사용에 관한 정보를 추적할 수도 있습니다. 예를들어, 시스템 프로세스에 관하여 다음과 같은 결과가 출력되었다고 합시다.

** MEMINFO in pid 890 [system] **
                    native   dalvik    other    total
            size:    10940     7047      N/A    17987
       allocated:     8943     5516      N/A    14459
            free:      336     1531      N/A     1867
           (Pss):     4585     9282    11916    25783
  (shared dirty):     2184     3596      916     6696
    (priv dirty):     4504     5956     7456    17916

 Objects
           Views:      149        ViewRoots:        4
     AppContexts:       13       Activities:        0
          Assets:        4    AssetManagers:        4
   Local Binders:      141    Proxy Binders:      158
Death Recipients:       49
 OpenSSL Sockets:        0

 SQL
            heap:      205          dbFiles:        0
       numPagers:        0   inactivePageKB:        0
    activePageKB:        0

가장 위에 "size" 항목은 이 프로세스에 할당된 전체 힙 영역의 크기를 나타내며, "allocated" 는 실재로 사용중인 힙 영역의 크기를 "free" 는 아직 할당되지 않은 힙 영역의 크기를 나타냅니다. 이 때 사용되는 단위는 KB 입니다. "pss" 와 "priv dirty" 는 앞서 설명한 내용과 동일합니다.

만일 여러분의 전체 프로세스의 메모리 사용에 관한 정보를 알고 싶다면 "adb shell procrank" 명령어를 사용할 수 있습니다. 해당 명령어를 사용하면 아래와 유사한 결과를 확인 할 수 있습니다.

  PID      Vss      Rss      Pss      Uss  cmdline
  890   84456K   48668K   25850K   21284K  system_server
 1231   50748K   39088K   17587K   13792K  com.android.launcher2
  947   34488K   28528K   10834K    9308K  com.android.wallpaper
  987   26964K   26956K    8751K    7308K  com.google.process.gapps
  954   24300K   24296K    6249K    4824K  com.android.phone
  948   23020K   23016K    5864K    4748K  com.android.inputmethod.latin
  888   25728K   25724K    5774K    3668K  zygote
  977   24100K   24096K    5667K    4340K  android.process.acore
...
   59     336K     332K      99K      92K  /system/bin/installd
   60     396K     392K      93K      84K  /system/bin/keystore
   51     280K     276K      74K      68K  /system/bin/servicemanager
   54     256K     252K      69K      64K  /system/bin/debuggerd

여기서 확인 할 수 있는 정보 중에 Vss 와 Rss 항목은 실재로는 전혀 쓸모가 없습니다. (이것들은 하나의 프로세스가 사용중인 RAM 영역의 크기를 직접 표시한 값인데, 공유된 메모리에 관한 고려가 없기 때문에 만일 이 값들을 모두 더해 본다면 실재 RAM 영역보다 훨씬 큰 값을 얻게 될 것입니다.)

Pss 는 앞서 설명한 값이며, Uss 는 Priv Dirty 를 의미하며 이 역시 앞서 설명한 내용입니다.

여기서 재미있는 점은 Pss 와 Uss 의 값이 우리가 meminfo 명령어를 통해 살펴본 내용과 조금 (혹은 조금 보다는 좀 더 많이) 다르다는 점 입니다. 왜 그럴까요? 흠. procrank 는 데이타를 모으는데 meminfo 와는 조금 다른 커널 메커니즘을 사용하기 때문에 그렇습니다. 왜 서로 다른 메카니즘을 사용할까요? 솔직히 말해 저도 잘 모르겠습니다. 개인적으로 prorcrank 가 좀더 정확하다고 믿고 있습니다만, 사실 별 상관은 없습니다. 대충 가감하여 두 값중에 원하는 값을 취하시면 됩니다.

마지막으로 시스템의 전반적인 메모리 사용량을 요약하여 살펴보기 위하여 "adb shell cat /proc/meminfo" 명령어를 사용할 수 있습니다. 굉장히 많은 데이터가 출력되겠지만, 첫 부분의 몇줄만 이야기할 가치가 있습니다. (나머지 내용들은 오직 소수의 사람들만이 이해할 수 있으며, 제가 그 소수에 사람들에게 관련된 내용을 질문해 보았지만 그 답이 늘 일정하지 않더군요.)

MemTotal:         395144 kB
MemFree:          184936 kB
Buffers:             880 kB
Cached:            84104 kB
SwapCached:            0 kB

MemTotal 은 실재 커널과 유저 스페이스에 사용 가능한 메모리 총량으로 일반적으로 실재 물리적인 RAM 크기보다는 작습니다. (RAM 의 일부분은 라디오나 DMA 버퍼등으로 사용되기 때문입니다.)

MemFree 는 전혀 사용되고 있지 않은 RAM 크기입니다. 여기 예시에 나온 수치는 매우 크지만, 일반적인 안드로이드 시스템에서 이 수치는 고작해야 몇 MB 에 그칠 것 입니다. 안드로이드는 메모리에 여유가 있는한 최대한 프로세스를 동작시키는데 사용하고자 노력하기 때문입니다.

Cached 는 파일 시스템이 캐쉬나 다른 일들을 위하여 사용하는 메모리 크기입니다. 일반적으로 안드로이드 시스템은 "Bad Paging State" 로 빠지는 것을 방지하기 위하여, 20MB 정도의 Cashed 영역을 필요로 합니다. 안드로이드의 메모리 킬러(메모리가 부족할 경우 백그라운드 프로세스를 종료시키는 모듈)는 백그라운드 포르세스가 Cached RAM 을 너무 많이 소비하기 전에 해당 프로세스를 종료시키는 방식으로 작동합니다.

 

출처 : 휴우님 블로그 http://blog.naver.com/PostView.nhn?blogId=huewu&logNo=110092658919&parentCategoryNo=18&viewDate=&currentPage=1&listtype=0


나눔글꼴 설치 안내


이 PC에는 나눔글꼴이 설치되어 있지 않습니다.

이 사이트를 나눔글꼴로 보기 위해서는
나눔글꼴을 설치해야 합니다.

설치 취소

Designed by sketchbooks.co.kr / sketchbook5 board skin

Sketchbook5, 스케치북5

Sketchbook5, 스케치북5

Sketchbook5, 스케치북5

Sketchbook5, 스케치북5