我们知道在Android系统中我们可以dump memory 信息.
adb shell dumpsys meminfo
例如:
Total RAM: 1899276 kB (status normal)
Free RAM: 1091614 kB(65910 cached pss + 514808 cached kernel + 510896 free)
Used RAM: 617959 kB(389287 used pss + 228672 kernel)
Lost RAM: 189703 kB
ZRAM: 4 kB physicalused for 0 kB in swap (524284 kB total swap)
Tuning: 128 (large 256), oom 322560 kB, restore limit 107520kB (high-end-gfx)
最重要的是以下几项:
典型的是物理内存大小-120M
2. Free RAM=cached pss +cached kernel +free.
因为cached memory 在内存紧张的时候会很快释放.
3.Used RAM =(totalPss - cachedPss)+KernelUsedSize
4. Lost RAM= Total RAM- Free RAM- Used RAM
dumpsys meminfo 只是android系统统计memory用法的一种方法.我们来看看Android 的计算方法
2. Free RAM
{
....
pw.print(" Free RAM: "); pw.print(cachedPss + memInfo.getCachedSizeKb() + memInfo.getFreeSizeKb()); pw.print(" kB ("); pw.print(cachedPss); pw.print(" cached pss + "); pw.print(memInfo.getCachedSizeKb()); pw.print(" cached kernel + "); pw.print(memInfo.getFreeSizeKb()); pw.println(" free)");
}
就是所有是cached的app,android 认为是可以用的,因为在android 内存紧张的时候LMK会被trigger,这类app 会被killed
b. cached kernel
public long getCachedSizeKb() { return mInfos[Debug.MEMINFO_BUFFERS] + mInfos[Debug.MEMINFO_CACHED] - mInfos[Debug.MEMINFO_MAPPED]; }
mInfos[Debug.MEMINFO_BUFFERS]: 所有的block dev map 到memory 中的buffer
mInfos[Debug.MEMINFO_CACHED]: pagecache
mInfos[Debug.MEMINFO_MAPPED]:map 到内存中的file或so所占用的buffer。所有map到的内存都在帕gecache中,所以这里需要减去map 部分的buffer。
c.free memory
public long getFreeSizeKb() { return mInfos[Debug.MEMINFO_FREE]; //free memory }
3.Used RAM
{
...
pw.print(" Used RAM: "); pw.print(totalPss - cachedPss + memInfo.getKernelUsedSizeKb()); pw.print(" kB ("); pw.print(totalPss - cachedPss); pw.print(" used pss + "); pw.print(memInfo.getKernelUsedSizeKb()); pw.print(" kernel)\n");
}
其实used RAM就是user space used RAM+kernel space used.
Kernel space used RAM
public long getKernelUsedSizeKb() { return mInfos[Debug.MEMINFO_SHMEM] + mInfos[Debug.MEMINFO_SLAB]+ mInfos[Debug.MEMINFO_VM_ALLOC_USED] + mInfos[Debug.MEMINFO_PAGE_TABLES]+ mInfos[Debug.MEMINFO_KERNEL_STACK]; }
包含 share memory,slab,vm alloc used,page table,kernel stack.
4. Lost RAM= Total RAM- Total RAM-Total Pss -Free RAM-Cached RAM-Kernel used RAM
{
.....
pw.print(" Lost RAM: "); pw.print(memInfo.getTotalSizeKb() - totalPss - memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb() - memInfo.getKernelUsedSizeKb()); pw.println(" kB");
}
e. Kernel used RAM
public long getKernelUsedSizeKb() { return mInfos[Debug.MEMINFO_SHMEM] + mInfos[Debug.MEMINFO_SLAB]+ mInfos[Debug.MEMINFO_VM_ALLOC_USED] + mInfos[Debug.MEMINFO_PAGE_TABLES]+ mInfos[Debug.MEMINFO_KERNEL_STACK]; }
这里meminfo数据来源都来自/proc/meminfo,下面是一份meminfo的例子
MemTotal: 2916948 kB
MemFree: 991164 kB
Buffers: 115616 kB
Cached: 926960 kB
SwapCached: 0 kB
Active: 603080 kB
Inactive: 803412 kB
Active(anon): 363960 kB
Inactive(anon): 2836 kB
Active(file): 239120 kB
Inactive(file): 800576 kB
Unevictable: 0 kB
Mlocked: 0 kB
SwapTotal: 524284 kB
SwapFree: 524284 kB
Dirty: 32 kB
Writeback: 0 kB
AnonPages: 364052 kB
Mapped: 215568 kB
Shmem: 2900 kB
Slab: 93224 kB
SReclaimable: 34916 kB
SUnreclaim: 58308 kB
KernelStack: 22480 kB
PageTables: 22388 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 1982756 kB
Committed_AS: 42865040 kB
VmallocTotal: 251658176 kB
VmallocUsed: 96896 kB
VmallocChunk: 251459492 kB
void si_meminfo(struct sysinfo *val) { val->totalram = totalram_pages; val->sharedram = 0; val->freeram = global_page_state(NR_FREE_PAGES); val->bufferram = nr_blockdev_pages(); val->totalhigh = totalhigh_pages; val->freehigh = nr_free_highpages(); val->mem_unit = PAGE_SIZE; }
然而这里的LostRAM 让人误解,以为系统有memoryleak.导致memory丢失.事实上这里的memory统计并不准确.我们在有的手机上可以看到LostRAM 为负数或者接近于0.而在有的手机上看到这个值很大.下面我们来分析其lostRAM 的来源.
Lost RAM 可能来自下面五个方面:
adb shell cat /sys/class/kgsl/kgsl/page_alloc //kgsl /1024/1024 gfx 分配的size
adb shell cat /sys/kernel/debug/ion/heaps/system //ION total /1024/1024