本文主要是介绍OOM和adj值的区分,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
内存管理模块——lowmemory killer和out-of-memory killer
1.文章概述
在项目debug时发现log中经常不断的触发lowemeory killer(以后简称LMK)机制去kill掉一些进程,后查明是在sharefolder时候配置init.qcom.post_boot.sh对LMK门限值设定出现遗漏,导致阀值过高,以至于LMK长期被触发,并占用了大量内存系统资源,浪费进程空间。让上层同事对此造成误会,特对此Memorykill做出简要描述。
2.LMK
Android Kernel会定时执行一次对内存的检查,如果达到一定阀值,则杀死一些进程,释放其内存,采用的就是Low memory kille机制。
LMK在计算kill进程时主要是通过进程的oom_adj值来判定进程的重要程度。这个值越小,程序越重要,被杀的可能性越低。
Low memory killer源码和具体实现可参看:kernel/drivers/misc/lowmemorykiller.c
2.1 LMK逻辑流程:
a.LMK开始工作时,首先根据阈值表确定当前的警戒级数,则高于警戒级数的进程是待杀的范围。
b.然后遍历所有进程的oom_adj值,找到大于min_adj的进程,若找到多个,则把占用进程最大的进程存放在selected中。
c.最后也是关键的一步就是,发送SIGKILL信息,杀掉该进程。
2.2 OOM和adj值的区分
oom_adj的大小和进程的类型以及进程被调度的次序有关。
Oom_adj在对进程类型进行分类的规则,可以在ActivityManagerService中清楚的看到:
3. staticfinal int EMPTY_APP_ADJ;
4. staticfinal int HIDDEN_APP_MAX_ADJ;
5. staticfinal int HIDDEN_APP_MIN_ADJ;
6. staticfinal int HOME_APP_ADJ;
7. staticfinal int BACKUP_APP_ADJ;
8. staticfinal int SECONDARY_SERVER_ADJ;
9. staticfinal int HEAVY_WEIGHT_APP_ADJ;
10. staticfinal int PERCEPTIBLE_APP_ADJ;
11. staticfinal int VISIBLE_APP_ADJ;
12. staticfinal int FOREGROUND_APP_ADJ;
13. staticfinal int CORE_SERVER_ADJ = -12;
14. staticfinal int SYSTEM_ADJ = -16;
其他未赋值的都在static块中进行了初始化,是通过system/rootdir/init.rc进行配置的,其配置信息如下:
在init.rc中:
15.# Define theoom_adj values for the classes of processes that can be
16.# killed by thekernel. These are used in ActivityManagerService.
17. setpropro.FOREGROUND_APP_ADJ 0
18. setpropro.VISIBLE_APP_ADJ 1
19. setpropro.SECONDARY_SERVER_ADJ 2
20. setpropro.HIDDEN_APP_MIN_ADJ 7
21. setpropro.CONTENT_PROVIDER_ADJ 14
22. setpropro.EMPTY_APP_ADJ 15
23.
24.# Define the memorythresholds at which the above process classes will
25.# bekilled. These numbers are in pages (4k).
26. setpropro.FOREGROUND_APP_MEM 1536
27. setpropro.VISIBLE_APP_MEM 2048
28. setpropro.SECONDARY_SERVER_MEM 4096
29. setpropro.HIDDEN_APP_MEM 5120
30. setpropro.CONTENT_PROVIDER_MEM 5632
31. setpropro.EMPTY_APP_MEM 6144
32.
而设计到LMK的配置文件有如下三个:
a) /sys/module/lowmemorykiller/parameters/adj
b) /sys/module/lowmemorykiller/parameters/minfree
c) Init.qcom.post_boot.sh
owmeme_adj:中各项数值代表阈值的警戒级数,
lowmem_minfree:代表对应级数的剩余内存。
Init.qcom.post_boot.sh:中可以配置Lmk不同阶段阀值大小。该文件适用于整机优化内容。而对于某些小内存设备,也可以手动调整对应的门限值,例如:
一般调整后三个值。
echo“1536,2048,4096,15360,17920,20480″>/sys/module/lowmemorykiller/parameters/minfree
而adj文件存放着oom_adj 内存警戒值( 以4K为单位)
cat到底信息如下:
0 1536
1 2048
2 4096
7 5120
14 5632
15 6144
上述参数的含义,当系统的剩余内存为小于6MB时候,警戒级数为0,当系统内存剩余小于8M而大于
6M的时候,警戒级数为1,当内存小于64M大于16MB的时候,警戒级数为12.
2.3 在init.rc中对LMK的配置
在init中可以找到如下配置:
# Write value mustbe consistent with the above properties.
write/sys/module/lowmemorykiller/parameters/adj 0,1,2,7,14,15
write/proc/sys/vm/overcommit_memory 1
write/sys/module/lowmemorykiller/parameters/minfree 1536,2048,4096,5120,5632,6144
进程oom_adj同样可以进行设置,通过write /proc/<PID>/oom_adj,在init.rc中,init进程的pid为1,omm_adj被配置为-16,永远不会被杀死。
#Set init its forked children's oom_adj.
write/proc/1/oom_adj -16
dumpsys activity可以dump进程的信息,查看adj值。procrank可以查看进程占用内存大小,当然也可以使用top或者cat mininfo等节点确定。
2.4 OOM Killer
Linux下还有一种OOM KILLER 的机制,如果上述各种方法(包括LMK)都无法释放出足够的内存空间,那么当为新的进程分配应用程序时将发生 Out-of-Memorykiller异常,OOM_killer 将尽最后杀掉一些进程来释放空间,它会在系统内存耗尽的情况下,启用自己算法有选择性的kill 掉一些进程。2.5 OOM原理
当我们使用应用时,需要申请内存,即进行malloc的操作,进行malloc操作如果返回一个非NULL的操作表示申请到了可用的内存。事实上,这个地方是可能存在bug的。Linux有一种内存优化机制,即:允许程序申请比系统可用内存更多的内存,但是Linux并不保证这些内存马上可用,如果凑 巧你申请到的内存中在你需要使用的时候还没有完全释放出来,这个时候就会触发OOM killer了。内核代码为:mm/oom_kill.c,其调用顺序为:malloc -> _alloc_pages -> out_of_memory() -> select_bad_process() -> badness()
OOM如何选择要kill掉的进程
分析badness代码,其选择过程如下:
1)计算该进程以及其子进程所占用的内存;
2)计算CPU时间和存活时间
3)做相应的权重调整
总结起来,就是占用内存越高,得分越高,cpu时间和存活时间越高,得分越低;进程优先级越高,得分越低
综合上述因素后,会得到一个point的值,得分最高的会被选中,然后被kill掉。
源码位于: oom_kill.c
这篇关于OOM和adj值的区分的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!