这是android对于linux原生的oom机制的改良,期望其能更有效的处理手持设备的oom. 它通过暴露出两个关键的接口
/sys/module/lowmemorykiller/parameters/adj
write /sys/module/lowmemorykiller/parameters/minfree
来控制oom的行为,使得系统在oom的时候,能够按照android的定义,选择合适的process来kill. 而不是按照标准linux的那种复杂计算逻辑选择process.
android会按照adj和minfree里面的设置, 分为几类(某人是6个slot), user通过设置对应process的oom_adj来告知lowmemorykiller什么条件下进行kill. 如下所示:
Android系统中对于lowmemorykiller的应用:
首先在device启动的init.rc脚本中会有相关的设置,如Cyanogemod的passion手机中的设置如下:
# Define the oom_adj values for the classes of processes that can be
# killed by the kernel. These are used in ActivityManagerService.#这里是相应类型的应用程序的adj值
setprop ro.FOREGROUND_APP_ADJ 0
setprop ro.VISIBLE_APP_ADJ 1
setprop ro.PERCEPTIBLE_APP_ADJ 2
setprop ro.HEAVY_WEIGHT_APP_ADJ 3
setprop ro.SECONDARY_SERVER_ADJ 4
setprop ro.BACKUP_APP_ADJ 5
setprop ro.HOME_APP_ADJ 6
setprop ro.HIDDEN_APP_MIN_ADJ 7
setprop ro.EMPTY_APP_ADJ 15
# Define the memory thresholds at which the above process classes will
# be killed. These numbers are in pages (4k).#这里是相应类型的应用程序所占用的内存值(minfree)
setprop ro.FOREGROUND_APP_MEM 2048
setprop ro.VISIBLE_APP_MEM 3072
setprop ro.PERCEPTIBLE_APP_MEM 4096
setprop ro.HEAVY_WEIGHT_APP_MEM 4096
setprop ro.SECONDARY_SERVER_MEM 6144
setprop ro.BACKUP_APP_MEM 6144
setprop ro.HOME_APP_MEM 6144
setprop ro.HIDDEN_APP_MEM 7168
setprop ro.EMPTY_APP_MEM 8192
# Write value must be consistent with the above properties.
# Note that the driver only supports 6 slots, so we have combined some of
# the classes into the same memory level; the associated processes of higher
# classes will still be killed first.
write /sys/module/lowmemorykiller/parameters/adj 0,1,2,4,7,15# Set init its forked children's oom_adj.
write /proc/1/oom_adj -16
其中adj定义了用户程序中与oom_adj相对应的最低限制, 当一个进程的minfree达到了
/sys/module/lowmemorykiller/parameters/minfree中所定义的一个下限,那么kernel就会去寻找这个minfree下限所对应的adj数值, 找到之后,会与用户侧的oom_adj的值比较, 用户进程中所有oom_adj大于等于adj的进程都会被lowmemorykiller选中, 然后按照各自的oom_adj排序,从而判断谁会被kill. 这里oom_adj的取值范围是-17~15, 值越大越容易被选中.framework会根据上诉init.rc中的种类, 动态的更改app的oom_adj的值, 比如一个app只有service在的时候,framework会使得它的oom_adj为9, 而当用户打开该app, 它这时变成了一个前台的app, 这时framework会把它的oom_adj改为0, 这样就与init.rc中定义的默认adj, freemem匹配起来了.
举例来说,
如果系统中的设置如下:
# cat /sys/module/lowmemorykiller/parameters/adj
0,1,2,4,7,15
# cat /sys/module/lowmemorykiller/parameters/minfree
2048,3072,4096,6144,7168,8192同时,一个process的oom_adj为0, 那么就表示, 如果它的空闲存储达到2048个page的时候, 因为它的oom_adj为0, 则它会被选中称为可以kill的候选者.
与之相关的framework层的代码如下:
frameworks/base/services/java/com/android/server/am/ActivityManagerService.java:UpdateOomAdjLocked(...)
and frameworks/base/core/java/android/os/Process.java:setOomAdj() => frameworks/base/core/jni/android_util_Process.cpp:android_os_Process_setOomAdj()
最后, 值得一提的是, lowmemorykiller的实现依然跟其它对kernel的扩展一样, 是基于已有kernel的体系结构和接口, 按照android对手持设备的理解,利用这些已有的接口,实现了android独有的机制. 这里, lowmemorykiller利用的是mm子系统中的shrinker接口, 通过mm子系统提供的register_shrinker这样的回调, 按照上述的判断条件, 通过global_page_state对page的检测, 来达到与mm子系统中对page管理功能的交互,从而实现lowmemorykiller的功能.(这里利用了这个callback, 打断了kernel的标准oom的流程!)
参考资料:
Android Kernel Features
<Android技术内幕>
标准的oom_adj的介绍: http://lwn.net/Articles/317814/
android对于kernel的扩展的介绍: http://www.lindusembedded.com/blog/2010/12/07/android-linux-kernel-additions/