目录
内存统计工具
/proc/meminfo
Buddy
Slub
Procrank
/proc/pid/smaps
Dumpsys meminfo
内存评估
内存泄漏
Lmk 水位调整
内存统计工具
/proc/meminfo

可以提供整体内存信息,各字段表示的意思如下:
|   字段  |   表示意思  | 
|   MemTotal  |   系统可以使用的总内存  | 
|   MemFree  |   buddy 里面所有 free 的 page 的数(不包括冷热页,目前也没有看见哪里统计 有冷热页)  | 
|   Buffers  |   块设备的缓存页(不属于某个具体文件的管理信息的缓存页)  | 
|   Cached  |   属于具体某个文件的缓存页  | 
|   SwapCached  |   swap cache 中的缓存页,其不包含在下面的 lru 中  | 
|   Active  |   系统中正在使用中的且使用的较积极的页  | 
|   Inactive  |   lru 系统中正在使用中的但是不太积极的页  | 
|   Active(anon)  |   Active 的匿名页  | 
|   Inactive(anon)  |   Inactive 的匿名页  | 
|   Active(file)  |   Active 的文件缓存页  | 
|   Inactive(file)  |   Inactive 的文件缓存页  | 
|   Unevictable  |   隔离的,暂时不参与 active/Inactive 判断的匿名页和文件缓存页之和  | 
|   SwapTotal  |   swap 分区总大小(对于 zram,是 zram 块设备的大小,而不是 zram 实际占用的大小)  | 
|   SwapFree  |   swap 分区 free 空间(对于 zram,是 zram 块设备剩余空间)  | 
|   Dirty  |   文件缓存中的脏页,如果这个地方很大,就要小心 IO 的配置或者 IO 有问题,比如之前有 Bug 将 dirty_ration 设置为 30%,就会出现这种情况  | 
|   Writeback  |   文件缓存中正在写回的页  | 
|   AnonPages  |   APP 所使用的匿名映射的 pages(没有被 swap 出去的部分)。基本就是 Active(anon)+ Inactive(anon)  | 
|   Mapped  |   mapped 文件的部分,其应该是 cached 的一个子集  | 
|   Slab  |   slab 占有的所有page. 如果user_debug 版本打开了slub 将显著的增大该项  | 
|   SReclaimable  |   其中设置为 Reclaimable 的 slab 占用的部分  | 
|   SUnreclaim  |   设置为 Unreclaim 的 slab 占用的部分  | 
|   KernelStack  |   每个线程(无论用户线程还是内核线程)都有一个 8K(arm32)的内核空间 线程栈  | 
|   PageTables  |   用户进程的二级页表 pte 项(不包括内核进程的),所以可以认为完全是用户 态占用  | 
|   VmallocTotal  |   内核 vmalloc 可以用的全部空间  | 
|   VmallocUsed  |   已经使用了的空间(但不一定是 vmalloc 分配了物理内存的)  | 
|   VmallocChunk  |   vmalloc 区域剩余的最大连续空间  | 
Buddy
分别是各个Order 的块的个数。Buddy 之和就是proc/meminfo 中free 的大小。

Slub
root@XXXX:/ # cat /proc/slabinfo slabinfo - version: 2.1
# name <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> : tunables
<limit> <batchcount> <sharedfactor> : slabdata <active_slabs> <num_slabs> <sharedavail> ext4_groupinfo_4k 61 156 104 39 1 : tunables 0 0 0 : slabdata
4 4 0
|   UDPLITEv6  |   0  |   0  |   768  |   21  |   4 : tunables  |   0  |   0  |   0 : slabdata  | ||||
|   0 0  |   0  | |||||||||||
|   UDPv6  |   1  |   42  |   768  |   21  |   4 : tunables  |   0  |   0  |   0 : slabdata  | ||||
|   2 2  |   0  | |||||||||||
|   ...  | ||||||||||||
|   kmalloc-4096  |   184  |   196  |   4096  |   4  |   4 : tunables  |   0  |   0  |   0 : slabdata  | ||||
|   49 49  |   0  | |||||||||||
|   kmalloc-2048  |   95  |   136  |   2048  |   8  |   4 : tunables  |   0  |   0  |   0 : slabdata  | ||||
|   17 17  |   0  | |||||||||||
|   kmalloc-1024  |   377  |   400  |   1024  |   16  |   4 : tunables  |   0  |   0  |   0 : slabdata  | ||||
|   25 25  |   0  | |||||||||||
|   kmalloc-512  |   918  |   1072  |   512  |   16  |   2 : tunables  |   0  |   0  |   0 : slabdata  | ||||
|   67 67  |   0  | |||||||||||
|   kmalloc-256  |   635  |   704  |   256  |   16  |   1 : tunables  |   0  |   0  |   0 : slabdata  | ||||
|   44 44  |   0  | |||||||||||
|   kmalloc-192  |   4726  |   4893  |   192  |   21  |   1 : tunables  |   0  |   0  |   0 : slabdata  | ||||
|   233 233  |   0  | |||||||||||
|   kmalloc-128  |   5501  |   6048  |   128  |   32  |   1 : tunables  |   0  |   0  |   0 : slabdata  | ||||
|   189 189  |   0  | |||||||||||
|   kmalloc-64  |   47242  |   48640  |   64  |   64  |   1 : tunables  |   0  |   0  |   0 : slabdata  | ||||
760 760 0
kmem_cache_node 76 256 64 64 1 : tunables 0 0 0 : slabdata 4 4 0
kmem_cache 76 160 128 32 1 : tunables 0 0 0 : slabdata 5 5 0
各项信息为:
<active_objs>:The number of objects (memory blocks) that are in use (allocated)
<num_objs>:总共现在有多少 memory blocks Objsize:The size of the objects.
Objperslab:每个 slab 有多少个 memory blocks Pagesperslab:每个 slab 占用多少个page(4096)。
Procrank
|   字段  |   表示意思  | 
|   VSS(virtual set size)  |   单个进程全部可访问的用户虚拟地址空间  | 
|   RSS(Resident set size)  |   单个进程实际占用的内存大小(所有共享库的全部内存大小)  | 
|   PSS(proportional set size)  |   不同于 RSS,它只是按比例包含其所使用的共享库大小。  | 
|   USS(Unique set size)  |   是单个进程的全部私有内存大小。  | 
|   Swap  |   某个进程被交换出去的匿名页的大小就是 Swap(包括在 swap cache 中的和 真正交换到 swap 分区的都算)。  | 
|   Pswap  |   模仿 PSS 的概念,因为每个匿名页可能会被多个进程使用。因此 Swap 中 的 page 按照目前还有多少进程使用它,按照比例分配得到 pswap。  | 
|   Uswap  |   模仿 Uss 的概念,私有的且被 swap 出去的内存的大小。  | 
127|root@XXXX:/ # procrank
|   PID  |   Vss  |   Rss  |   Pss  |   Uss  |   Swap PSwap cmdline  | |||
|   1237  |   1128200K  |   108136K  |   55922K  |   52196K  |   1388K 1388K system_server  | |||
|   1390  |   732552K  |   105912K  |   52002K  |   46884K  |   52K 52K  | |||
|   com.android.systemui  | ||||||||
|   1977 1028756K  |   81440K  |   31869K  |   28868K  |   0K  |   0K  | |||
|   com.android.launcher3  | ||||||||
|   3474 1058820K  |   75688K  |   22556K  |   17464K  |   0K  |   0K  | |||
|   com.sds.android.ttpod:channel  | ||||||||
|   3343  |   1301320K  |   67968K  |   20864K  |   16336K  |   0K  |   0K com.tencent.mm  | ||
|   ...  | ||||||||
|   186  |   9172K  |   1448K  |   208K  |   160K  |   692K  |   692K  |   /system/bin/vold  | |
|   224  |   4748K  |   928K  |   172K  |   160K  |   256K  |   256K  | ||
|   /system/bin/download  | ||||||||
|   325  |   3092K  |   1100K  |   165K  |   20K  |   0K  |   0K  |   /system/xbin/srtd  | |
|   362  |   3092K  |   460K  |   152K  |   20K  |   0K  |   0K  |   /system/xbin/srtd  | |
|   207  |   3104K  |   928K  |   80K  |   64K  |   232K  |   232K  |   /system/bin/lmkd  | |
|   252  |   3036K  |   804K  |   68K  |   12K  |   312K  |   312K  |   /system/bin/sh  | |
|   213  |   7824K  |   844K  |   65K  |   52K  |   256K  |   256K  | ||
|   /system/bin/modemd  | ||||||||
|   218  |   988K  |   96K  |   64K  |   64K  |   56K  |   56K  |   /bin/batterysrv  | |
|   194  |   5284K  |   1192K  |   54K  |   24K  |   464K  |   464K  | ||
|   /system/bin/gatekeeperd  | ||||||||
|   225  |   5108K  |   792K  |   40K  |   28K  |   228K  |   228K  | ||
/system/bin/gnss_download 212 4708K 792K 17K 4K 284K 284K
/system/bin/modem_control 219 4860K 748K 16K 4K 284K 284K
/system/bin/modemDriver_vpad_main 195 2800K 804K 15K 0K 308K 308K
/system/xbin/perfprofd 627540K 492360K 10772K 10619K TOTAL
RAM: 939244K total, 19076K free, 8768K buffers, 365548K cached, 4024K shmem, 34248K slab
/proc/pid/smaps
这个是对进程地址空间以及内存使用,最全面的展示。各项说明参考:
6f387000-6ff18000 rw-p 00000000 b3:15 7575 /data/dalvik-cache/arm/system@framework@boot.art
|   Size:  |   11844 kB  |   该段虚拟空间大小  | 
|   Rss:  |   11828 kB  |   = Shared_Clean+ Shared_Dirty+ Private_Clean+ Private_Dirty= Filecache+  | 
|   Anonymous Pss:  |     2179 kB  |     = Pss_Filecache+ Pss_Anonymous  | 
|   Uss:  |   1304 kB  |   = Private_Filecache+Private_Anonymou  | 
|   Shared_Clean:  |   7964 kB  |   和其它进程共享而且是干净的  | 
|   Shared_Dirty:  |   2560 kB  |   和其它进程共享而且是脏的  | 
|   Private_Clean:  |   616 kB  |   本进程私有而且是干净的  | 
|   Private_Dirty: Referenced: Filecache:  |   688 kB 11544 kB 8580 kB  |   本进程私有而且是脏的 文件缓存 = Shared_Filecache+ Private_Filecache  | 
|   Pss_Filecache:  |   1344 kB  |   按比例共享的文件缓存  | 
|   Shared_Filecache:  |   7964 kB  |   多进程共享的文件缓存  | 
|   Private_Filecache:  |   616 kB  |   私有的文件缓存  | 
|   Anonymous:  |   3248 kB  |   匿名内存 = Shared_Anonymous+ Private_Anonymous  | 
|   Pss_Anonymous:  |   835 kB  |   按比例共享的匿名内存  | 
|   Shared_Anonymous:  |   2560 kB  |   多进程共享的匿名内存  | 
|   Private_Anonymous: AnonHugePages: Swap:  |   688 kB 0 kB 0 kB  |   私有的匿名内存 进程被交换出去的匿名页  | 
|   PSwap:  |   0 kB  |   按比例共享的被交换出去的匿名页  | 
|   USwap: KernelPageSize: MMUPageSize: Locked:  |   0 kB 4 kB 4 kB 0 kB  |   私有的被交换出去的匿名页  | 
VmFlags: rd wr mr mw me ac mg
Dumpsys meminfo
Dumpsys meminfo 是 android 提供的比较有用的内存信息统计工具,并且结合了进程的 adj,可以查看各组进程所占的内存情况。

各个数据的统计来自/proc/pid/smaps,对应关系请参考:
|   dumpsys meminfo  |    smaps line  |    特殊计算  | 
|    Native Heap  |   [heap] [anon:libc_malloc]XXX  | |
|    Dalvik Heap  |   .Heap+.LOS+.NonMoving +.Zygote  | |
|    Dalvik Other  |    .LinearAlloc+.Indirec tRef+.JITCache+.GC  | |
|   Stack  |   [stackXXX  | |
|     Ashmem  |   /dev/ashmemXXX (-/dev/ashmem/dalvik-XXX -/dev/ashmem/CursonrWindowXXX -/dev/ashmem/libc mallocXXX)  | 
|   Gfx dev  |   /dev/kgsl-3d0XXX  | |
|    Other dev  |   /dev/ (-/dev/kgsl-3d0 -/dev/ashmem)  | |
|    .so mmap  |   XXX.so 共享库的 bss 段  | |
|   .jar mmap  |   XXX.jar  | |
|   .apk mmap  |   XXX.apk  | |
|   .ttf mmap  |   XXX.ttf  | |
|    .dex mmap  |   XXX.dex XXX.odex  | |
|   .oat mmap  |   XXX.oat  | |
|   .art mmap  |   XXX.art  | |
|   Other mmap  |   namelen>0,已经统计的情况除外  | |
|   EGL mtrack  | ||
|   GL mtrack  | ||
|   Other mtrack  | ||
|   Unknow  |   [anonXXX|new mapping  | |
|   Dalvik Details  | ||
|    .Heap  |   /dev/ashmem/dalvik-alloc space /dev/ashmem/dalvik-main space  | |
|   .Los  |   /dev/ashmem/dalvik-large object space  | |
|   .LinearAlloc  |   /dev/ashmem/dalvik-LinearAlloc  | |
|    .GC  |   /dev/ashmem/dalvik-XXX (-heap_dalvik- (.LinearAlloc,.IndirectRef,.JitCache))  | |
|   .JITCache  |   /dev/ashmem/dalvik-jit-code-cache  | |
|   .Zygote  |   /dev/ashmem/dalvik-zygote space  | |
|   .NonMoving  |   /dev/ashmem/dalvik-non moving space  | |
|   .IndirectRef  |   /dev/ashmem/dalvik-indirect ref  | 
App Summary(主要是用来体现进程独占的那些内存)
|      Java Heap:  |     Private Dirty(Dalvik Heap) + Private Clean(.art) + Private Dirty(.art)  |      该进程独有 Java Heap  |   这个有点问题的, .art比较复杂也会包含文件缓存的(而从经验上看Private Clean(.art) 全部是Private_Filecache; 而Private Dirty(.art) 全部 是 Private_Anonymous)  | 
|    Native Heap:  |    Private Dirty(Native Heap)  |   该进程独有的 Native Heap  | |
|      Code:  |     Private(.so) + Private(.jar)+Private(.apk)+Private(. ttf)+Private(.dex)+Private(.oat)  |     该进程独有的代码占用的内存  |   .so 其实并不完全是 Code,其也包 含.data, .rodat .bss。这个参考意义有限,因为mmap 部分动态变化且不好统计的  | 
|    Stack:  |    Private Dirty(Stack)  |    该进程独有的栈内存  | |
|     Graphics:  |    Private(Gfx_dex) + Private(EGL mtrack) + Private(GL mtrack)  | ||
|      Private Other:  |    Private(Native Heap) + Private(Dalvik Heap) + Private(Unknow) -Java Heap-Native Heap - Code -Stack - Graphics  |       剩余的独有的部分  |   即:TOTAL(private) - Java Heap - Native Heap - Code - Stack - Graphics(应该就是Dalvik Other+Ashmem+Unkno w)  | 
|     System:  |   Pss(Dalvik Heap) + Pss(Native Heap) +Pss(Unknow)-Private(Dalvik Heap)-Private(Native Heap)-Private(Unknow)  |     和其它进程共享的,就算做系统的部分。  |   即:TOTAL(Pss) -TOTAL(Private)。 就是指和其他进程有共享的,就算系统占用的PSS 部分  | 
|   dumpsys meminfo  |   smaps  |   备注  | |
|   Pss Total  |   Pss:  | 
|       Pss Clean  |     sharing_proportion=(pss-priv ate_clean-private_dirty)/(shar ed_clean+shared_dirty) sharing_proportion*shared_c lean + private_clean  |   前提条件: 
 (shared_clean>0|shared_di rty>0)  |      这个就只统计这几 部分,其它的不管。所以 heap 的都为 0  | 
|   Shared Dirty  |   Shared_Dirty:  |   共享的脏的  | |
|   Private Dirty  |   Private_Dirty:  |   独占的脏的  | |
|   Shared Clean  |   Shared_Clean:  |   共享的干净的  | |
|   Private Clean  |   Private_Clean  |   独占的干净的  | |
|   Swapped Dirty  |   Swap:  |   被交换出去的  | |
|   Private Swapped  |   Uswap  |   独有的,被交换出去的  | |
|   Pss Swapped  |   Pswap  |   按比例被交换出去的  | |
|   Heap Size(Native Heap)  |    mallinfo->usmblks  |   程序申请内存的最 高值  | |
|   Heap Alloc(Native Heap)  |    mallinfo->uordblks  |   当前正在使用的内 存大小  | |
|   Heap Free(Native Heap)  |    mallinfo->fordblks  |   当前空闲的内存大 小  | |
|   Heap Size(Dalvik Heap)  |    Runtime.totalMemory()  |   Xms 参数指定  | |
|   Heap Alloc(Dalvik Heap)  |    Heap Size - Heap Free  | ||
|   Heap Free(Dalvik Heap)  |    Runtime.freeMemory()  | 
内存评估
有时需要评估二个版本或者同一个版本二种场景下的系统内存情况。比如某公司项目发现,插 sim 比不插 sim,性能差,想看看这二种情况下的内存情况。
首先,可以收集信息,看看同样在开机5分钟的场景下,FreeRAM 的差异。下面的数据可以从/proc/meminfo 和 dumpsys meminfo 中获得。

其次,看下这多出的内存都用在哪里了。

 


从上面可以,看出,二种场景主要是 framework+app 的内存差异,那进一步看下,用户空间的内存使用情况。下面数据可以由dumpsys meminfo 与 procrank得出。
 由上面的数据分析,可以得出结论:
插 sim 卡时,FreeRAM 少 40M。是因为上层 app 会多,从收集的数据看,会多占 60M内存。因此,会 drop 更多的file cache, swap 更多匿名页。而 Free RAM是强依赖 file cache,file cache 少,FreeRAM 也会少。
内存泄漏
当系统稳定性不好,或者 lmk 杀到 adj 很低时,一般会看下此时内存使用情况(同内存评估的表格),排查内存泄漏问题。这样整体上看,只能定位出哪个模块或者进程存在 memory leak,具体的 leak 点还需要各个 FO 排查。内核很少出现这类问题,一旦怀疑是内核出现 leak,就会采取很脏的方式,标记每个分配路径与回收路径,最终统计定位出问题的点,一般是 patch 形式 debug。
但是用户层的 memory leak 却很常见,一般泄漏的是 malloc 或者 new 后没有对应的 free 掉,导致Active(anon)+ Inactive(anon) + ZRAM 很大。
例:
从下面 LMK 杀进程时的 mem 情况,看到 Free memory 较小,而 swapfree为 0,swap 分区耗尽。
[82916.745910] c3 sprd thm: @@@D thm sensor id:0, cal_offset:-2, rawdata:0x3b4 
[82916.765411] c1 lowmemorykiller: Killing 'd.process.acore' (27571), adj 5, 
[82916.765411] c1	to free 11576kB on behalf of 'sdcard' (1590) because 
[82916.765411] c1	cache 17680kB is below limit 18432kB for oom_score_adj 3 
[82916.765411] c1	 Free memory is 4124kB above reserved
[82916.765411] c1	swaptotal is 409596kB, swapfree is 0kB 
进程的 RSS 信息和 swap 信息如下,而此时 mediaserver 占用空间特别大,用户空间 RSS 为 50M, 而swap 空间为 379M。基本可以确认是 mediaserver 内存泄漏。
lowmemorykiller: [ pid ] uid tgid total_vm rss swap cpu oom_score_adj name
|   lowmemorykiller: [  |   130]  |   0  |   130  |   175  |   48  |   62  |   3  |   -1000 ueventd  | 
|   lowmemorykiller: [  |   155]  |   1023  |   155  |   1028  |   51  |   45  |   0  |   -1000 sdcard  | 
|   lowmemorykiller: [  |   156]  |   1036  |   156  |   1497  |   51  |   112  |   2  |   -1000 logd  | 
|   lowmemorykiller: [  |   157]  |   0  |   157  |   395  |   44  |   2  |   3  |   -1000 healthd  | 
|   lowmemorykiller: [  |   158]  |   0  |   158  |   592  |   58  |   50  |   0  |   -1000 lmkd  | 
|   lowmemorykiller: [  |   159]  |   1000  |   159  |   309  |   58  |   30  |   0  |   -1000 servicemanager  | 
|   lowmemorykiller: [  |   160]  |   0  |   160  |   1447  |   33  |   144  |   1  |   -1000 vold  | 
|   lowmemorykiller: [  |   161]  |   0  |   161  |   545  |   48  |   175  |   0  |   -1000 debuggerd  | 
|   lowmemorykiller: [  |   162]  |   1000  |   162  |   10559  |   207  |   173  |   3  |   -1000 surfaceflinger  | 
|   lowmemorykiller: [  |   163]  |   0  |   163  |   782  |   10  |   43  |   0  |   -1000 modem_control  | 
|   lowmemorykiller: [  |   164]  |   1000  |   164  |   1559  |   3  |   57  |   3  |   -1000 modemd  | 
|   lowmemorykiller: [  |   165]  |   1000  |   165  |   1515  |   43  |   70  |   0  |   -1000 wcnd  | 
|   lowmemorykiller: [  |   166]  |   1000  |   166  |   88  |   0  |   12  |   3  |   -1000 batterysrv  | 
|   lowmemorykiller: [  |   173]  |   2000  |   173  |   278  |   21  |   41  |   1  |   -1000 sh  | 
|   lowmemorykiller: [  |   174]  |   0  |   174  |   1444  |   41  |   66  |   1  |   -1000 collect_apr  | 
|   lowmemorykiller: [  |   176]  |   0  |   176  |   2681  |   20  |   85  |   3  |   -1000 netd  | 
|   lowmemorykiller: [  |   177]  |   1019  |   177  |   4535  |   92  |   278  |   1  |   -1000 drmserver  | 
|   lowmemorykiller: [  |   178]  |   1013  |   178  |   146988  |   7926  |   92832  |   1  |   -1000 mediaserver  | 
Lmk 水位调整
在低内存手机中,常常会涉及 lmk 水位的调整,因为 android 原生水位相对高,常会出现闪退问题或者 CTS 测试进程被 kill。Lmk 水位调整是一种权衡,不会解决所有问题,只能根据项目的性能&稳定性目标,做出均衡。
根据项目经验,以下是Tuning 的大体策略:
- 基本原则是以 Android 计算的原生值为基准,不建议偏差太多。但是我们实际发现原生计算值比较大,多后台性能不怎么好;而且运行大应用会出现闪退。
 - 各 minfree 值档位差,最好依据原生的比例,尽量进行模仿。我们只是定最高水位 adj 15 对应的内存值。
 - 当系统 ANR 较多时(注:并不是说 ANR 就一定和 LMK 参数相关;但是调节 LMK 参数可以缓解系统的 ANR 情况)
 - 加大 oom_adj >= 9(HIDDEN_APP_MIN_ADJ)对应的 minfree 值
 - 但该方法会降低多后台的性能(减少后台 APP 个数)
 - 通过系统更为积极的 kill 进程来释放 mem;以降低内存回收所使用的 CPU,以及占用的 IO 带宽;加快进程获取 mem 的速度。
 - 如果想提高多后台:
 
- 同时应注意与 HIDDEN_APP_MIN_ADJ(9)以下的 adj 对应的 minfree
 - 调低 oom_adj >= 9(HIDDEN_APP_MIN_ADJ)对应 minfree 的值的值保持一定距离
 - 该方法和上述需求 1 是矛盾的。多后台和减少 ANR 往往会不可兼得,请根据实际需求综合考虑。
 - 如果要避免前台进程发生闪退: 
- 如果该值太低,系统内存极低时可能无法恢复过来,导致定屏黑屏等等。
 - 调低 FOREGROUND_APP_ADJ 0 对应的 minfree 值
 
 
- 如果觉得两个水位之间,间隔太大,没有积极的杀进程(主要是导致性能问 题),可以重新设定Oom_adj 数组,比如设定为:0,1,3,9,11,15(原生值为 0,1, 2,3,9,15)。
 - 调节起点:如果 swapfree 相当小时(小于 5%),但 ANON 页和 Filecache 都很大,而且由于 Filecache 很多,没有杀进程。则至少需要将最高杀 APP 水位调整到此时 Filecache 最大值。通过积极的杀进城来释放 swap 的空间,并减轻内存回收的压力。
 
下面是实际 tuning 的操作方法:
如果存在页颠簸的话,我们还是希望通过 lmk kill 进程来快速回收内存。而 lmk 参考的阀值是 file-cache,那我们可以大概估算出低于 adj 9 所有进程所需的总体 active file-cache,这值可以做为 adj9 的lmk 阀值。有了这个值,再根据原生水位的比例,就可以得出一组 lmk 水位。
一般将上面得到的水位做为系统最不积极的水位(水位再低点,就会出现页颠簸了),然后在这组水位与原生水位之间再设计出几套水位,再加一组比原生水位高点的水位。分别对设计出来的几套水位,进行性能与稳定性测试,选定表现最均衡的一组。
操作方法:
手机开机5分钟:
1)kill 所有后台进程(am kill-all);
2 ) 回收内存(echo 1 > /proc/sys/vm/drop_caches);
3)2 操作后,马上收集内存信息,/proc/meminfo, dumpsys meminfo -a;
- active file-cache 可以做为 adj 529 的内存阀值 base(minfree 数组的第 5 个值,注意除 4);
 - 再根据原生水位的比例,设计一组 lmk 水位;
 
最后,依据 dumpsys meminfo,查看各组进程组的内存占用情况,进行 minfree微调;