dumpsysとは
Androidのsystem serviceの状態を出力するコマンド。
オプション無しだと全サービスの情報を出力してくれる。
dumpsys -l
で対応するserviceの一覧を取得し、dumpsys SERVICE
で特定のserviceの情報だけ出力することも可能。
dumpsys自体はserviceに対してdump要求を投げるだけで、実際の情報出力はservice側でおこなう。
この作りのおかげで柔軟にdumpsysを拡張できる。
逆に言えばdumpsysに対応するserviceはシステムごとに異なる。
以前"cpuinfo"、"storaged"を取り上げたので、今回はメモリ使用量のスナップショット情報を取得する"meminfo"の中身を見る。
ソースコードおよび動作確認の環境は以下のとおり。
- Android: android-8.1.0_r1.0, Oreo, API 27
- Linux kernel: android-4.4-o-release
dumpsys meminfo
"meminfo"は、公式ドキュメントやヘルプがある。
起動引数
$ adb shell dumpsys meminfo -h
meminfo dump options: [-a] [-d] [-c] [-s] [--oom] [process]
-a: include all available information for each process.
-d: include dalvik details.
-c: dump in a compact machine-parseable representation.
-s: dump only summary of application memory usage.
-S: dump also SwapPss.
--oom: only show processes organized by oom adj.
--local: only collect details locally, don't call process.
--package: interpret process arg as package, dumping all
processes that have loaded that package.
--checkin: dump data for a checkin
If [process] is specified it can be the name or
pid of a specific process to dump.
さらにヘルプに記載されていないオプションに、--unreachable
がある。
これはApplicationInfo.FLAG_DEBUGGABLE
が有効な場合にlibmemunreachable
の機能を使ってメモリリークの可能性がある箇所をリストアップしてくれるという機能だ。
ご丁寧に、メモリの先頭20バイトのダンプまで出力してくれる。
なぜヘルプに記載がないのか不明だが、ぜひ覚えておきたい。
Unreachable memory
3432 bytes in 17 unreachable allocations
ABI: 'x86'
640 bytes unreachable at cfef6280
first 20 bytes of contents:
cfef6280: 47 4c 5f 4f 45 53 5f 45 47 4c 5f 69 6d 61 67 65 GL_OES_EGL_image
cfef6290: 20 47 4c 5f 4f 45 53 5f 45 47 4c 5f 69 6d 61 67 GL_OES_EGL_imag
出力
dumpsys meminfo
には大きくわけて2種類の情報を出力できる。
システム全体のメモリ使用状況と、特定のプロセスのメモリ使用状況だ。
システム全体のメモリ使用状況
[process]
を指定しなければ、システム全体のメモリ使用状況が取得できる。
$ adb shell dumpsys meminfo
Applications Memory Usage (in Kilobytes):
Uptime: 185142393 Realtime: 185142393
Total PSS by process:
78,971K: system (pid 1739)
73,453K: com.android.settings (pid 10066 / activities)
71,166K: com.google.android.googlequicksearchbox:search (pid 7671)
57,813K: com.android.chrome (pid 11345 / activities)
57,128K: com.google.android.gms (pid 2729)
...
Total PSS by OOM adjustment:
102,762K: Native
11,378K: webview_zygote32 (pid 2069)
11,023K: zygote (pid 1575)
8,693K: logd (pid 1346)
78,971K: System
78,971K: system (pid 1739)
61,158K: Persistent
42,552K: com.android.systemui (pid 2043)
18,606K: com.android.phone (pid 2093)
111,012K: Foreground
57,813K: com.android.chrome (pid 11345 / activities)
35,663K: com.android.chrome:sandboxed_process2 (pid 12159)
17,536K: com.android.chrome:privileged_process0 (pid 11502)
173,964K: Visible
71,166K: com.google.android.googlequicksearchbox:search (pid 7671)
49,281K: com.google.android.gms.persistent (pid 2006)
40,302K: com.google.android.apps.nexuslauncher (pid 2599 / activities)
96,534K: Perceptible
57,128K: com.google.android.gms (pid 2729)
39,406K: com.google.android.inputmethod.latin (pid 2020)
83,369K: Previous
73,453K: com.android.settings (pid 10066 / activities)
9,916K: com.google.android.setupwizard (pid 7497)
99,770K: Cached
19,102K: com.google.android.apps.messaging:rcs (pid 12059)
16,077K: com.google.android.calendar (pid 11846)
14,184K: com.google.android.gms.ui (pid 12618)
Total PSS by category:
222,003K: Native
154,210K: .dex mmap
114,120K: .apk mmap
79,066K: .so mmap
69,293K: Dalvik
37,480K: .oat mmap
35,128K: .art mmap
31,648K: Dalvik Other
22,808K: Unknown
21,870K: Other mmap
13,680K: Stack
2,183K: .ttf mmap
1,938K: Ashmem
1,935K: Other dev
178K: .jar mmap
0K: Cursor
0K: Gfx dev
0K: EGL mtrack
0K: GL mtrack
0K: Other mtrack
Total RAM: 1,530,828K (status normal)
Free RAM: 593,970K ( 99,770K cached pss + 224,260K cached kernel + 269,940K free)
Used RAM: 790,706K ( 707,770K used pss + 82,936K kernel)
Lost RAM: 146,152K
Tuning: 384 (large 384), oom 184,320K, restore limit 61,440K (high-end-gfx)
-
Total PSS by process
- プロセス単位でPSS(Proportional Set Size)が多いものから順に表示される。
- 1個以上のActivityを持つプロセスには
activities
と表示される。
-
Total PSS by OOM adjustment
- OOMのADJクラスごとのPSS値。
- 殺されにくいクラスから順に並ぶ。
- ADJクラスの一覧は、
dumpsys activity oom
で確認可能。-
()
内の値はプロセスを終了する閾値。 - 閾値はカーネルモジュール
lowmemorykiller
のパラメータとして設定される。 -
ActivityManager
がsocket経由でLMK_TARGET
コマンドを設定値とともにをlmkd
に送り、lmkd
がカーネルモジュールパラメータを設定する。
-
$ adb shell dumpsys activity oom
OOM levels:
-900: SYSTEM_ADJ ( 73,728K)
-800: PERSISTENT_PROC_ADJ ( 73,728K)
-700: PERSISTENT_SERVICE_ADJ ( 73,728K)
0: FOREGROUND_APP_ADJ ( 73,728K)
100: VISIBLE_APP_ADJ ( 92,160K)
200: PERCEPTIBLE_APP_ADJ ( 110,592K)
300: BACKUP_APP_ADJ ( 129,024K)
400: HEAVY_WEIGHT_APP_ADJ ( 147,456K)
500: SERVICE_ADJ ( 147,456K)
600: HOME_APP_ADJ ( 147,456K)
700: PREVIOUS_APP_ADJ ( 147,456K)
800: SERVICE_B_ADJ ( 147,456K)
900: CACHED_APP_MIN_ADJ ( 147,456K)
906: CACHED_APP_MAX_ADJ ( 184,320K)
...
$ adb shell cat /sys/module/lowmemorykiller/parameters/adj
0,100,200,300,900,906
$ adb shell cat /sys/module/lowmemorykiller/parameters/minfree
18432,23040,27648,32256,36864,46080
// These are the various interesting memory levels that we will give to
// the OOM killer. Note that the OOM killer only supports 6 slots, so we
// can't give it a different value for every possible kind of process.
private final int[] mOomAdj = new int[] {
FOREGROUND_APP_ADJ, VISIBLE_APP_ADJ, PERCEPTIBLE_APP_ADJ,
BACKUP_APP_ADJ, CACHED_APP_MIN_ADJ, CACHED_APP_MAX_ADJ
};
// These are the low-end OOM level limits. This is appropriate for an
// HVGA or smaller phone with less than 512MB. Values are in KB.
private final int[] mOomMinFreeLow = new int[] {
12288, 18432, 24576,
36864, 43008, 49152
};
// These are the high-end OOM level limits. This is appropriate for a
// 1280x800 or larger screen with around 1GB RAM. Values are in KB.
private final int[] mOomMinFreeHigh = new int[] {
73728, 92160, 110592,
129024, 147456, 184320
};
-
Total PSS by category
-
/proc/[pid]/smaps
から用途ごとのメモリ使用量を全プロセス分を集計し、多いものから順に表示される。 -
Native
:[heap]
,[anon:libc_malloc]
,/dev/ashmem/libc malloc
-
Dalvik
orDalvik Other
:/dev/ashmem/dalvik-
- Dalvik関連については、
-d
オプションを指定することで更に詳細な情報が出力される。
- Dalvik関連については、
-
Stack
:[stack]
- 対応は、frameworks/base/core/jni/android_os_Debug.cpp
-
-
Total RAM
:/proc/meminfo
のMemTotal
。つまり、カーネルが認識している物理メモリの総量。-
status
:ActivityManager
が各プロセスに設定するmemory trimming level。normal
,moderate
,low
,critical
のいずれか。PROCESS_STATE_CACHED_ACTIVITY
,PROCESS_STATE_CACHED_ACTIVITY_CLIENT
,PROCESS_STATE_CACHED_EMPTY
のプロセス数で決定される。これらのプロセスが多いほど、プロセスを終了することでメモリを回収できるため、プロセス単位でのmemory trimming levelは低くなる。 -
critical
:numCached <= 5
&&numEmpty <= 8
&&numCached+numEmpty <= 3
-
low
:numCached <= 5
&&numEmpty <= 8
&&3 < numCached+numEmpty <= 5
-
moderate
:numCached <= 5
&&numEmpty <= 8
&&5 < numCached+numEmpty
-
normal
: 上記以外
-
$ adb shell dumpsys activity settings | grep CUR_TRIM
CUR_TRIM_EMPTY_PROCESSES=8
CUR_TRIM_CACHED_PROCESSES=5
// Threshold of number of cached+empty where we consider memory critical.
static final int TRIM_CRITICAL_THRESHOLD = 3;
// Threshold of number of cached+empty where we consider memory critical.
static final int TRIM_LOW_THRESHOLD = 5;
-
Free RAM
: いつでも回収可能なメモリ。以下3つのメモリの和。-
cached pss
: いつでも殺していいプロセスのPSSの合計値。-
oomAdj
がCACHED_APP_MIN_ADJ(900)
以上のプロセスのPSS。 -
CACHED_APP_MIN_ADJ
以上ということは、裏に回っているactivityを持っているだけのプロセスを指し、終了させたとしてもユーザに影響しない。 - なおPSSなので、該当プロセスを終了したとしても厳密にこの分だけ解放されるわけではない(他のプロセスもマップしている共有ライブラリは、それらに再分配される)。
-
-
cached kernel
: カーネルでキャッシュ用途に使われているメモリのうち、プロセスにマッピングされていないメモリの量。-
/proc/meminfo
のBuffers+SReclaimable+Cached-Mapped
。
-
-
free
:/proc/meminfo
のMemFree
。つまり、まだどの用途にも使われていないメモリの量。
-
-
Used RAM
: 使用中のメモリ。以下2つのメモリの和。-
used pss
: 全プロセスのPSSの合計 -cached pss
。DirtyなページだけでなくCleanなページも含む。 -
kernel
: Kernelで使用中のメモリ。-
/proc/meminfo
のShmem+SUnreclaim+VmallocUsed+PageTables+KernelStack
。 - ただし、
VmallocUsed
だけはより正確にするために/proc/vmallocinfo
を使って再計算している。
-
-
/**
* Amount of RAM that is in use by the kernel for actual allocations.
*/
public long getKernelUsedSizeKb() {
return mInfos[Debug.MEMINFO_SHMEM] + mInfos[Debug.MEMINFO_SLAB_UNRECLAIMABLE]
+ mInfos[Debug.MEMINFO_VM_ALLOC_USED] + mInfos[Debug.MEMINFO_PAGE_TABLES]
+ mInfos[Debug.MEMINFO_KERNEL_STACK];
}
static void android_os_Debug_getMemInfo(JNIEnv *env, jobject clazz, jlongArray out)
{
...
// Recompute Vmalloc Used since the value in meminfo
// doesn't account for I/O remapping which doesn't use RAM.
mem[MEMINFO_VMALLOC_USED] = get_allocated_vmalloc_memory() / 1024;
...
-
Lost RAM
: ざっくりTotalRAM - FreeRAM - UsedRAM
(swapありだとちょっと違うが)。- 本当は0になってほしいがメモリ集計外のKernelAPIでメモリを確保している場合や、複数プロセスで二重に計上してしまうメモリなどの影響で出てしまった誤差。
- 負の値を取ることもある。
- 例えば巨大なファイルをtmpfsに置くと、
memInfo.getFreeSizeKb(MemFree)
が減る一方で、memInfo.getCachedSizeKb(Cached)
とmemInfo.getKernelUsedSizeKb(Shmem)
の両方が増えるため、lostRAM
は負の値になる。
long lostRAM = memInfo.getTotalSizeKb() - (totalPss - totalSwapPss)
- memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
- memInfo.getKernelUsedSizeKb() - memInfo.getZramTotalSizeKb();
-
KSM
: KSM (Kernel same-page Merging)発生時のみ表示される。-
/sys/kernel/mm/ksm/
以下から収集している。
-
-
ZRAM
: ZRAM使用時のみ表示される。
- AndroidではZRAMをswapとして使うことができる。
-/proc/meminfo
のZRam
(ZRAMが物理的に使用しているサイズ(圧縮後))
-/proc/meminfo
のSwapTotal-SwapFree
(スワップアウトしているサイズ(圧縮前))
-/proc/meminfo
のSwapTotal
(スワップ領域として確保されているサイズ) -
Tuning
特定のプロセスのメモリ使用状況
$ adb shell dumpsys meminfo com.android.chrome
Applications Memory Usage (in Kilobytes):
Uptime: 188982591 Realtime: 188982591
** MEMINFO in pid 11345 [com.android.chrome] **
Pss Private Private SwapPss Heap Heap Heap
Total Dirty Clean Dirty Size Alloc Free
------ ------ ------ ------ ------ ------ ------
Native Heap 16013 15968 0 0 25728 22402 3325
Dalvik Heap 2242 2200 0 0 5682 2841 2841
Dalvik Other 1190 1188 0 0
Stack 476 476 0 0
Ashmem 811 128 0 0
Other dev 227 200 24 0
.so mmap 2565 148 284 0
.apk mmap 22009 100 10380 0
.ttf mmap 241 0 168 0
.dex mmap 5445 12 2388 0
.oat mmap 2544 0 0 0
.art mmap 1785 1516 0 0
Other mmap 1537 4 940 0
Unknown 616 616 0 0
TOTAL 57701 22556 14184 0 31410 25243 6166
App Summary
Pss(KB)
------
Java Heap: 3716
Native Heap: 15968
Code: 13480
Stack: 476
Graphics: 0
Private Other: 3100
System: 20961
TOTAL: 57701 TOTAL SWAP PSS: 0
Objects
Views: 136 ViewRootImpl: 1
AppContexts: 3 Activities: 1
Assets: 4 AssetManagers: 6
Local Binders: 59 Proxy Binders: 42
Parcel memory: 10 Parcel count: 40
Death Recipients: 5 OpenSSL Sockets: 0
WebViews: 0
SQL
MEMORY_USED: 0
PAGECACHE_OVERFLOW: 0 MALLOC_SIZE: 0
出力フォーマット
出力フォーマットの変更も対応している。
こちらもcompact形式(-c
)とcheckin(--checkin
)の2種類がある。
compact形式(-c
)
他のプログラムで解釈しやすいようにCSV形式でコンパクトに出力する。
システム全体のメモリ使用状況を出力するときのみ有効。
$ adb shell dumpsys meminfo -c
version,1
time,187036613,187036613
oom,native,102696,N/A
proc,native,/init,1,1545,N/A,e
proc,native,ueventd,1052,1076,N/A,e
proc,native,logd,1346,8705,N/A,e
proc,native,servicemanager,1347,620,N/A,e
列1 | 列2 | 列3 | 列4 | 列5 | 列6 | 列7 | 説明 |
---|---|---|---|---|---|---|---|
version |
フォーマットバージョン | ||||||
time |
uptime (ミリ秒) |
realtime (ミリ秒) |
|||||
proc |
tag |
shortLabel |
id |
pss |
swapPss |
hasActivities |
Total PSS by process 相当 |
oom |
shortLabel |
pss |
swapPss |
Total PSS by OOM adjustment 相当 |
|||
cat |
shortLabel |
pss |
swapPss |
Total PSS by category 相当 |
|||
ram |
getTotalSizeKb() (KiB) |
Free RAM (KiB) |
used pss (KiB) |
Total RAM , Free RAM , Used RAM 相当 |
|||
lostram |
lostRAM |
Lost RAM 相当 |
|||||
zram |
getZramTotalSizeKb() |
getSwapTotalSizeKb() |
getSwapFreeSizeKb() |
ZRAM 相当 |
|||
ksm |
KSM_SHARING |
KSM_SHARED |
KSM_UNSHARED |
KSM_VOLATILE |
KSM 相当 |
||
tuning |
? | ? | ? | ? |
Tuning 相当 |
checkin
$ adb shell dumpsys meminfo --checkin
time,186992273,186992273
4,11345,com.android.chrome,25728,5723,N/A,31451,22492,2862,N/A,25354,3235,2861,N/A,6096,16001,2762,39461,58224,0,0,13220,13220,1056,1168,5296,7520,0,0,136112,136112,15956,2720,4396,23072,0,0,14184,14184,0,0,\
0,0,0,0,0,0,Dalvik Other,1198,0,60,0,1196,0,0,0,Stack,476,0,4,0,476,0,0,0,Cursor,0,0,0,0,0,0,0,0,Ashmem,811,0,1380,12,128,0,0,0,Gfx dev,0,0,0,0,0,0,0,0,Other dev,227,0,80,120,200,24,0,0,.so mmap,2565,284,270\
8,30004,148,284,0,0,.jar mmap,0,0,0,0,0,0,0,0,.apk mmap,22009,10380,0,40384,100,10380,0,0,.ttf mmap,241,168,0,424,0,168,0,0,.dex mmap,5449,2388,0,25212,12,2388,0,0,.oat mmap,2546,0,60,31044,0,0,0,0,.art mmap\
,1786,0,808,6000,1516,0,0,0,Other mmap,1537,0,16,2912,4,940,0,0,EGL mtrack,0,0,0,0,0,0,0,0,GL mtrack,0,0,0,0,0,0,0,0,Other mtrack,0,0,0,0,0,0,0,0,136,1,3,1,4,6,59,42,5,1,0,0,0,0
4,7671,com.google.android.googlequicksearchbox:search,21376,6998,N/A,28374,17573,5249,N/A,22822,3802,1749,N/A,5551,10805,5176,52874,68855,0,0,24320,24320,1060,1208,3944,6212,0,0,141848,141848,10760,5132,7972\
,23864,0,0,24556,24556,0,0,0,0,0,0,0,0,Dalvik Other,4522,0,60,0,4520,0,0,0,Stack,684,0,4,0,684,0,0,0,Cursor,0,0,0,0,0,0,0,0,Ashmem,2,0,4,12,0,0,0,0,Gfx dev,0,0,0,0,0,0,0,0,Other dev,158,0,76,120,0,156,0,0,.s\
o mmap,2031,0,2708,29844,148,0,0,0,.jar mmap,0,0,0,0,0,0,0,0,.apk mmap,12468,5288,0,32416,228,5288,0,0,.ttf mmap,84,0,0,464,0,0,0,0,.dex mmap,27569,18956,0,41460,28,18956,0,0,.oat mmap,2310,76,60,29116,0,76,\
0,0,.art mmap,1752,0,844,6000,1480,0,0,0,Other mmap,414,0,16,2416,4,80,0,0,EGL mtrack,0,0,0,0,0,0,0,0,GL mtrack,0,0,0,0,0,0,0,0,Other mtrack,0,0,0,0,0,0,0,0,144,1,8,1,5,5,42,32,0,0,706,706,144,117,/data/user\
/0/com.google.android.googlequicksearchbox/app_si/state_dump_event_content_store/content_store.db,4,40,55,5/47/4,5/47/4,/data/user/0/com.google.android.googlequicksearchbox/app_si/state_dump_event_content_st\
ore/content_store.db (2),4,40,19,0/14/1,0/14/1,/data/user/0/com.google.android.googlequicksearchbox/app_si/now_content_store/content_store.db,4,40,19,0/60/1,0/60/1,/data/user/0/com.google.android.googlequick\
searchbox/app_si/now_content_store/content_store.db (2),4,40,36,3/33/2,3/33/2
実装
使い方や出力例は公式等に任せるとして、実装を追ってみる。
meminfo
Serviceの登録は、cpuinfo
と同じくAcitivityManagerService::setSystemProcess()
で行われる。
public void setSystemProcess() {
try {
ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);
ServiceManager.addService(ProcessStats.SERVICE_NAME, mProcessStats);
ServiceManager.addService("meminfo", new MemBinder(this));
ServiceManager.addService("gfxinfo", new GraphicsBinder(this));
ServiceManager.addService("dbinfo", new DbBinder(this));
if (MONITOR_CPU_USAGE) {
ServiceManager.addService("cpuinfo", new CpuBinder(this));
}
ServiceManager.addService("permission", new PermissionController(this));
ServiceManager.addService("processinfo", new ProcessInfoService(this));
...
}
}
dumpsys meminfo
実行時は、MemBinder::dump()
が呼び出され、処理はActivityManagerService::dumpApplicationMemoryUsage()
に委譲される。
static class MemBinder extends Binder {
ActivityManagerService mActivityManagerService;
MemBinder(ActivityManagerService activityManagerService) {
mActivityManagerService = activityManagerService;
}
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpAndUsageStatsPermission(mActivityManagerService.mContext,
"meminfo", pw)) return;
mActivityManagerService.dumpApplicationMemoryUsage(fd, pw, " ", args, false, null);
}
}
ActivityManagerService::dumpApplicationMemoryUsage()
の最初でオプションの処理を行う。
final void dumpApplicationMemoryUsage(FileDescriptor fd,
PrintWriter pw, String prefix, String[] args, boolean brief, PrintWriter categoryPw) {
...
while (opti < args.length) {
String opt = args[opti];
if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') {
break;
}
opti++;
if ("-a".equals(opt)) {
dumpDetails = true;
dumpFullDetails = true;
dumpDalvik = true;
dumpSwapPss = true;
...
ActivityManagerService::dumpApplicationMemoryUsage()
はとても長い関数だが、実際にメモリ使用量を収集しているのは、下記の3箇所。
-
Debug::getMemoryInfo()
: 特定のPIDの詳細メモリ情報。/proc/<pid>/smaps
を解析する。mapされているファイルの拡張子(.so
,.jar
,.apk
等)ごとに分類。 -
Debug.getPss()
: 特定のPIDのPSS。/proc/<pid>/smaps_rollup
を解析する。 -
IApplicationThread::dumpMemInfo()
: プロセスヒープの詳細(後述)。
final void dumpApplicationMemoryUsage(FileDescriptor fd,
PrintWriter pw, String prefix, String[] args, boolean brief, PrintWriter categoryPw) {
...
for (int i = procs.size() - 1 ; i >= 0 ; i--) {
...
if (thread != null) {
if (!isCheckinRequest && dumpDetails) {
pw.println("\n** MEMINFO in pid " + pid + " [" + r.processName + "] **");
}
...
if (dumpDetails || (!brief && !oomOnly)) {
Debug.getMemoryInfo(pid, mi);
hasSwapPss = mi.hasSwappedOutPss;
} else {
mi.dalvikPss = (int)Debug.getPss(pid, tmpLong, null);
mi.dalvikPrivateDirty = (int)tmpLong[0];
}
if (dumpDetails) {
if (localOnly) {
...
} else {
pw.flush();
try {
TransferPipe tp = new TransferPipe();
try {
thread.dumpMemInfo(tp.getWriteFd(),
mi, isCheckinRequest, dumpFullDetails,
dumpDalvik, dumpSummaryOnly, dumpUnreachable, innerArgs);
tp.go(fd);
} finally {
tp.kill();
}
...
}
}
}
...
}
}
ActivityThread::dumpMemInfo()
では、下記の情報を収集、出力する。
- Native Heap
- Size :
mallinfo(3)
のusmblks
(Maximum total allocated space) - Alloc :
mallinfo(3)
のuordblks
(Total allocated space) - Free :
mallinfo(3)
のfordblks
(Total free space)
- Size :
- Dalvik Heap
- Size :
JVM_TotalMemory()
- Alloc :
JVM_TotalMemory() - JVM_FreeMemory()
- Free :
JVM_FreeMemory()
- Size :
- Java Object個数(タイプ別)
- この時、正確にObject個数を集計するため、Garbage Collectionが走る。
- SQLite使用メモリ
これらの情報と、前述のDebug::getMemInfo
等で取得した情報を併せて出力する。
private void dumpMemInfo(PrintWriter pw, Debug.MemoryInfo memInfo, boolean checkin,
boolean dumpFullInfo, boolean dumpDalvik, boolean dumpSummaryOnly, boolean dumpUnreachable) {
long nativeMax = Debug.getNativeHeapSize() / 1024;
long nativeAllocated = Debug.getNativeHeapAllocatedSize() / 1024;
long nativeFree = Debug.getNativeHeapFreeSize() / 1024;
Runtime runtime = Runtime.getRuntime();
runtime.gc(); // Do GC since countInstancesOfClass counts unreachable objects.
long dalvikMax = runtime.totalMemory() / 1024;
long dalvikFree = runtime.freeMemory() / 1024;
long dalvikAllocated = dalvikMax - dalvikFree;
なお、Debug
classは下記でJNIとしてC++で実装されている。
static const JNINativeMethod gMethods[] = {
{ "getNativeHeapSize", "()J",
(void*) android_os_Debug_getNativeHeapSize },
{ "getNativeHeapAllocatedSize", "()J",
(void*) android_os_Debug_getNativeHeapAllocatedSize },
{ "getNativeHeapFreeSize", "()J",
(void*) android_os_Debug_getNativeHeapFreeSize },
{ "getMemoryInfo", "(Landroid/os/Debug$MemoryInfo;)V",
(void*) android_os_Debug_getDirtyPages },
{ "getMemoryInfo", "(ILandroid/os/Debug$MemoryInfo;)V",
(void*) android_os_Debug_getDirtyPagesPid },
{ "getPss", "()J",
(void*) android_os_Debug_getPss },
{ "getPss", "(I[J[J)J",
(void*) android_os_Debug_getPssPid },
{ "getMemInfo", "([J)V",
(void*) android_os_Debug_getMemInfo },
{ "dumpNativeHeap", "(Ljava/io/FileDescriptor;)V",
(void*) android_os_Debug_dumpNativeHeap },
{ "dumpNativeMallocInfo", "(Ljava/io/FileDescriptor;)V",
(void*) android_os_Debug_dumpNativeMallocInfo },
{ "getBinderSentTransactions", "()I",
(void*) android_os_Debug_getBinderSentTransactions },
{ "getBinderReceivedTransactions", "()I",
(void*) android_os_getBinderReceivedTransactions },
{ "getBinderLocalObjectCount", "()I",
(void*)android_os_Debug_getLocalObjectCount },
{ "getBinderProxyObjectCount", "()I",
(void*)android_os_Debug_getProxyObjectCount },
{ "getBinderDeathObjectCount", "()I",
(void*)android_os_Debug_getDeathObjectCount },
{ "dumpJavaBacktraceToFileTimeout", "(ILjava/lang/String;I)Z",
(void*)android_os_Debug_dumpJavaBacktraceToFileTimeout },
{ "dumpNativeBacktraceToFileTimeout", "(ILjava/lang/String;I)Z",
(void*)android_os_Debug_dumpNativeBacktraceToFileTimeout },
{ "getUnreachableMemory", "(IZ)Ljava/lang/String;",
(void*)android_os_Debug_getUnreachableMemory },
};
まとめ
dumpsys meminfo
は便利で複雑なのでついつい全情報を出力したくなるが、
内部的には/proc/pid/smaps
の解析やGCの実行など、かなり重たい処理が実行される。
定期的に実行する場合はオプションを適切に使って出来る限り軽量にモニタするようにしたい。