目录
[Dumpsys meminfo](#Dumpsys meminfo)
[Lmk 水位调整](#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 | 前提条件: 1. XXX.so||XXX.jar||XXX. apk|XXX.ttf|XXX.dex|XX X.odex|XXX.oat|XXX.art 2. pss>0 & (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 分区耗尽。
cpp
[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微调;