我们知道在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)
最重要的是以下几项:
- Total RAM = physic memory –modem memory –reservememory
典型的是物理内存大小-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 的计算方法
- Total RAM 很简单就是Android 系统所能用到的memory
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)");
}
- cachedPss if (oomAdj >= ProcessList.CACHED_APP_MIN_ADJ) { cachedPss = myTotalPss; }
就是所有是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.
- User space used RAM totalPss - cachedPss
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");
}
- Total RAM public long getTotalSizeKb() { return mInfos[Debug.MEMINFO_TOTAL]; }
- Total Pss
- Free RAM public long getFreeSizeKb() { return mInfos[Debug.MEMINFO_FREE]; }
- Cached RAM public long getCachedSizeKb() { return mInfos[Debug.MEMINFO_BUFFERS] mInfos[Debug.MEMINFO_CACHED] - mInfos[Debug.MEMINFO_MAPPED]; }
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
- MemTotal: Total usable RAM in kilobytes (i.e. physical memory minus a few reserved bytes and the kernel binary code)
- MemFree: The amount of physical RAM left unused by the system.
- Buffers: The amount of physical RAM used for file buffers.
- Cached: The amount of physical RAM used as cache memory. Memory in the pagecache (diskcache) minus SwapCache.
- SwapCache: This is the amount of Swap used as cache memory. Memoy that once was swapped out, is swapped back in, but is still in the swapfile.
- Active: The total amount of buffer or page cache memory, that is active. This part of the memory is used recently and usually not reclaimed unless absolutely necessary.
- Inactive: The total amount of buffer or page cache memory that are free and available. This is memory that has not been recently used and can be reclaimed for other purposes by the paging algorithm.
- SwapTotal: Total amount of physical swap memory.
- SwapFree: Total amount of swap memory free.
- Dirty: The total amount of memory waiting to be written back to the disk.
- Writeback: The total amount of memory actively being written back to the disk.
- Committed_AS: An estimate of how much RAM you would need to make a 99.99% guarantee that there never is OOM (out of memory) for this workload. Normally the kernel will overcommit memory. This parameter represents the worst case scenario value, and also includes swap memory.
- DirectMap: This is x86 specific, basically available direct mapped slots. This is the number of pages mapped as 4KB pages, 2MB/4MB pages, and 1GB pages if supported and used. The direct mapping covers all memory in the system up to the highest memory address.
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 可能来自下面五个方面:
- ION. 我们知道很多多媒体的应用使用ION 来分配memory的.大多数芯片供应商是没有把这部分Memory map到process中, 也就没有统计在cached 中.而ION为了分配效率会把这部分用过的memory 先cached 以便下次使用的时候直接从cache中分配, 从而加快了分配速度, 提高了系统性能.而当系统的memory吃紧时, 这部分cached memory 会free.这往往是Lost RAM 的主要来源.
- KGSL. Graphic 系统分配的内存.这边分内存可能已经map到了process 中, 也有可能没有map 到process中, 取决于芯片厂商的实现. 如果没有map到process ,这也是Lost RAM的重要来源.
- ZRAM 中被用掉的部分
- 多次计算用过的memory,例如filecache ,DSS等.常见的Lost RAM 为负数就是这个原因.
- 其它计算不准备的memory. 事实上我们可以从其它memoryinfo 来确定是否有memory leak 或其它问题. adb shell pull /d/ion your folder //可以检查heaps来确定cached ION memory. adb shell cat /d/kgsl/proc/*/mem > kgsl_mem.txt //可以用例看每个processgfx 所用的memory. adb shel cat /proc/meminfo //获得更准确的memoryinfo adb shell cat /d/shrinker //查看可以free 的memory大小及其优先级.
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