<wbr><wbr><wbr> 那么,如何来判断,那些进程是需要杀死的呢?答案就是我们的标题:Low memory killer机制。</wbr></wbr></wbr>
<wbr><wbr><wbr> Android 的Low memory killer是基于linux的OOM(out of memory)<wbr> 规则改进而来的。 OOM通过一些比较复杂的评分机制,对进程进行打分,然后将分数高的进程判定为bad进程,杀死并释放内存。OOM只有当系统内存不足的时候才会启动检查,而Low memory killer 则是定时进行检查。</wbr></wbr></wbr></wbr>
<wbr><wbr><wbr> Low memory killer 主要是通过进程的oom_adj 来判定进程的重要程度。oom_adj的大小和进程的类型以及进程被调度的次序有关。</wbr></wbr></wbr>
<wbr><wbr><wbr> Low memory killer 的具体实现可参看:kernel/drivers/misc/lowmemorykiller.c<wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr> 其原理很简单,在linux中,存在一个kswapd的内核线程,当linux回收存放分页的时候,kswapd线程将会遍历一张<strong><em>shrinker</em></strong>链表,并执行回调,定义如下:</wbr></wbr></wbr>
<wbr><wbr><wbr><wbr>所以只要注册 Shrinker,变可以在内存分页回收时根据规则释放内存,下面我们来看看其实现。<wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr>首先定义shrinker结构体,lowmem_shrink为回调函数的指针,当有内存分页回收的时候,这个函数将会被调用。</wbr></wbr></wbr>
<wbr></wbr>
<wbr><wbr> 初始化模块时进行注册,结束时注销。</wbr></wbr>
<wbr><wbr><wbr><wbr>Android中,存在着一张内存阈值表,这张阈值表是可以在init.rc中进行配置的,</wbr></wbr></wbr></wbr>
合理配置这张表,对于小内存设备有非常重要的作用。
<wbr><wbr><wbr> 我们来看lowmemorykiller.c中这张默认的阈值表:</wbr></wbr></wbr>
<wbr></wbr>
<wbr></wbr>
Lowmeme_adj中各项数值代表阈值的警戒级数,lowmem_minfree代表对应级数的剩余内存。
也就是说,当系统的剩余内存为小于6MB时候,警戒级数为0,当系统内存剩余小于8M而大于
6M的时候,警戒级数为1,当内存小于64M大于16MB的时候,警戒级数为12.
Low memory killer 的规则就是根据当前系统的剩余内存多少来获取当前的警戒级数,如果进程的oom_adj大于警戒级数并且最大,进程将会被杀死(相同omm_adj的,则杀死占用内存较多的)。Omm_adj越小,代表进程越重要。一些前台的进程,oom_adj会比较小,而后台的服务,omm_adj会比较大,所以当内存不足的时候,Low memory killer 杀掉的必然先杀掉的是后台服务而不是前台的进程。
OK,现在我们来看具体代码,也就是lowmem_shrink这个回调函数:
<wbr></wbr>
<wbr></wbr>
首先通过global_page_state获取当前剩余内存大小,然后根据剩余内存和内存阈值表查找当前的内存警戒数min_adj。接着遍历所有进程,找到oom_adj大于min_adj并且oom_adj最大的进程:
进程的oom_adj 小于警戒阈值,则无视。<wbr></wbr>
获取这个进程所占用的内存大小tasksize,如果小于比我们当前选出进程的内存,则无视。
如果大于则选中这个进程:
经过for_each的遍历,selected 就是我们选出要释放掉的bad进程,它具有下面两个条件:
Oom_adj大于当前警戒阈值并且最大。
在同样大小的oom_adj中,占用内存最多。
<wbr></wbr>
最后,我们释放掉这个进程的内存,通过force_sig(SIGKILL, selected)来向进程发送一个不可以忽略或阻塞的SIGKILL信号。
<wbr></wbr>
阈值表可以通过/sys/module/lowmemorykiller/parameters/adj和/sys/module/lowmemorykiller/parameters/minfree进行配置,例如在init.rc中:
# Write value must be consistent with the above properties.
<wbr><wbr></wbr></wbr>write /sys/module/lowmemorykiller/parameters/adj 0,1,2,7,14,15
<wbr></wbr>
<wbr><wbr></wbr></wbr>write /proc/sys/vm/overcommit_memory 1
<wbr><wbr></wbr></wbr>write /sys/module/lowmemorykiller/parameters/minfree 1536,2048,4096,5120,5632,6144
<wbr></wbr>
<wbr><wbr></wbr></wbr>class_start default
<wbr></wbr>
<wbr></wbr>
进程oom_adj同样可以进行设置,通过write /proc/<PID>/oom_adj <wbr></wbr>,在init.rc中,init进程的pid为1,omm_adj被配置为-16,永远不会被杀死。
<wbr><wbr></wbr></wbr># Set init its forked children's oom_adj.
<wbr><wbr></wbr></wbr>write /proc/1/oom_adj -16
<wbr></wbr>
<wbr><wbr><wbr>Low memory killer的基本原理我们应该弄清了,正如我前面所说的,进程omm_adj的大小是跟进程的类型以及进程被调度的次序有关。进程的类型,可以在<span style="color:black">ActivityManagerService</span><span style="color:black">中清楚的看到:</span><wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr> static final int EMPTY_APP_ADJ;</wbr></wbr></wbr>
<wbr><wbr><wbr> static final int HIDDEN_APP_MAX_ADJ;</wbr></wbr></wbr>
<wbr><wbr><wbr> static final int HIDDEN_APP_MIN_ADJ;</wbr></wbr></wbr>
<wbr><wbr><wbr> static final int HOME_APP_ADJ;</wbr></wbr></wbr>
<wbr><wbr><wbr> static final int BACKUP_APP_ADJ;</wbr></wbr></wbr>
<wbr><wbr><wbr> static final int SECONDARY_SERVER_ADJ;</wbr></wbr></wbr>
<wbr><wbr><wbr> static final int HEAVY_WEIGHT_APP_ADJ;</wbr></wbr></wbr>
<wbr><wbr><wbr> static final int PERCEPTIBLE_APP_ADJ;</wbr></wbr></wbr>
<wbr><wbr><wbr> static final int VISIBLE_APP_ADJ;</wbr></wbr></wbr>
<wbr><wbr><wbr> static final int FOREGROUND_APP_ADJ;</wbr></wbr></wbr>
<wbr><wbr><wbr> static final int CORE_SERVER_ADJ = -12;</wbr></wbr></wbr>
<wbr><wbr><wbr> static final int SYSTEM_ADJ = -16;<wbr></wbr></wbr></wbr></wbr>
<wbr><wbr> ActivityManagerService</wbr></wbr>定义各种进程的oom_adj,CORE_SERVER_ADJ代表一些核心的服务的omm_adj,数值为-12,由前面的分析可知道,这类进程永远也不会被杀死。
其他未赋值的都在static块中进行了初始化,是通过system/rootdir/init.rc进行配置的:
<wbr></wbr>
<wbr><wbr> 在init.rc中:</wbr></wbr>
# Define the oom_adj values for the classes of processes that can be
# killed by the kernel.<wbr></wbr>
<wbr><wbr></wbr></wbr>
<wbr><wbr></wbr></wbr>
<wbr><wbr></wbr></wbr>
<wbr><wbr></wbr></wbr>
<wbr><wbr></wbr></wbr>
<wbr><wbr></wbr></wbr>
<wbr></wbr>
# Define the memory thresholds at which the above process classes will
# be killed.<wbr></wbr>
<wbr><wbr></wbr></wbr>
<wbr><wbr></wbr></wbr>
<wbr><wbr></wbr></wbr>
<wbr><wbr></wbr></wbr>
<wbr><wbr></wbr></wbr>
<wbr><wbr></wbr></wbr>
<wbr></wbr>
<wbr><wbr>由此我们知道<span style="color:black">EMPTY_APP</span> <span style="color:black"> 最容易被杀死,其实是</span><span style="color:black">CONTENT_PROVIDER</span> <span style="color:black"> ,</span><span style="color:black">FOREGROUND</span><span style="color:black">的进程很难被杀死。</span></wbr></wbr>
<wbr><wbr></wbr></wbr>现在我们再来说影响oom_adj的第二个因素,进程的调度次序。这涉及到了ActivityManagerService的复杂调度,我们下次再来看吧。呵呵。