网站开发顺序,中国筑建网官网,wordpress好的主题,舟山市建设信息港网站Android Low memorykillerby 永远的伊苏Android中#xff0c;进程的生命周期都是由系统控制的#xff0c;即使用户关掉了程序#xff0c;进程依然是存在于内存之中。这样设计的目的是为了下次能快速启动。当然#xff0c;随着系统运行时间的增长#xff0c;内存会越来越少…Android Low memorykillerby 永远的伊苏Android中进程的生命周期都是由系统控制的即使用户关掉了程序进程依然是存在于内存之中。这样设计的目的是为了下次能快速启动。当然随着系统运行时间的增长内存会越来越少。Android Kernel 会定时执行一次检查杀死一些进程释放掉内存。那么如何来判断那些进程是需要杀死的呢答案就是我们的标题Low memory killer机制。Android 的Low memorykiller是基于linux的OOM(out of memory) 规则改进而来的。 OOM通过一些比较复杂的评分机制对进程进行打分然后将分数高的进程判定为bad进程杀死并释放内存。OOM只有当系统内存不足的时候才会启动检查而Low memory killer 则是定时进行检查。Lowmemory killer 主要是通过进程的oom_adj来判定进程的重要程度。oom_adj的大小和进程的类型以及进程被调度的次序有关。Lowmemory killer 的具体实现可参看kernel/drivers/misc/lowmemorykiller.c其原理很简单在linux中存在一个kswapd的内核线程当linux回收存放分页的时候kswapd线程将会遍历一张shrinker链表并执行回调定义如下所以只要注册Shrinker变可以在内存分页回收时根据规则释放内存,下面我们来看看其实现。首先定义shrinker结构体lowmem_shrink为回调函数的指针当有内存分页回收的时候这个函数将会被调用。初始化模块时进行注册结束时注销。Android中存在着一张内存阈值表这张阈值表是可以在init.rc中进行配置的合理配置这张表对于小内存设备有非常重要的作用。我们来看lowmemorykiller.c中这张默认的阈值表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这个回调函数首先通过global_page_state获取当前剩余内存大小然后根据剩余内存和内存阈值表查找当前的内存警戒数min_adj。接着遍历所有进程找到oom_adj大于min_adj并且oom_adj最大的进程进程的oom_adj小于警戒阈值则无视。获取这个进程所占用的内存大小tasksize如果小于比我们当前选出进程的内存则无视。如果大于则选中这个进程:经过for_each的遍历selected 就是我们选出要释放掉的bad进程它具有下面两个条件Oom_adj大于当前警戒阈值并且最大。在同样大小的oom_adj中占用内存最多。最后我们释放掉这个进程的内存通过force_sig(SIGKILL, selected)来向进程发送一个不可以忽略或阻塞的SIGKILL信号。阈值表可以通过/sys/module/lowmemorykiller/parameters/adj和/sys/module/lowmemorykiller/parameters/minfree进行配置例如在init.rc中# Write value must be consistent with the above properties.write /sys/module/lowmemorykiller/parameters/adj 0,1,2,7,14,15write /proc/sys/vm/overcommit_memory 1write /sys/module/lowmemorykiller/parameters/minfree 1536,2048,4096,5120,5632,6144class_start default进程oom_adj同样可以进行设置通过write/proc//oom_adj在init.rc中init进程的pid为1omm_adj被配置为-16永远不会被杀死。# Set init its forked childrens oom_adj.write /proc/1/oom_adj -16Low memory killer的基本原理我们应该弄清了正如我前面所说的进程omm_adj的大小是跟进程的类型以及进程被调度的次序有关。进程的类型可以在ActivityManagerService中清楚的看到static final int EMPTY_APP_ADJ;static final int HIDDEN_APP_MAX_ADJ;static final int HIDDEN_APP_MIN_ADJ;static final int HOME_APP_ADJ;static final int BACKUP_APP_ADJ;static final int SECONDARY_SERVER_ADJ;static final int HEAVY_WEIGHT_APP_ADJ;static final int PERCEPTIBLE_APP_ADJ;static final int VISIBLE_APP_ADJ;static final int FOREGROUND_APP_ADJ;static final int CORE_SERVER_ADJ -12;static final int SYSTEM_ADJ -16;ActivityManagerService定义各种进程的oom_adj,CORE_SERVER_ADJ代表一些核心的服务的omm_adj,数值为-12由前面的分析可知道这类进程永远也不会被杀死。其他未赋值的都在static块中进行了初始化是通过system/rootdir/init.rc进行配置的在init.rc中# Define the oom_adj values for the classes ofprocesses that can be# killed by the kernel. These are used inActivityManagerService.setprop ro.FOREGROUND_APP_ADJ 0setprop ro.VISIBLE_APP_ADJ 1setprop ro.SECONDARY_SERVER_ADJ 2setprop ro.HIDDEN_APP_MIN_ADJ 7setprop ro.CONTENT_PROVIDER_ADJ 14setprop ro.EMPTY_APP_ADJ 15# Define the memory thresholds at which the aboveprocess classes will# be killed. These numbers are inpages (4k).setprop ro.FOREGROUND_APP_MEM 1536setprop ro.VISIBLE_APP_MEM 2048setprop ro.SECONDARY_SERVER_MEM 4096setprop ro.HIDDEN_APP_MEM 5120setprop ro.CONTENT_PROVIDER_MEM 5632setprop ro.EMPTY_APP_MEM 6144由此我们知道EMPTY_APP 最容易被杀死其实是CONTENT_PROVIDER FOREGROUND的进程很难被杀死。现在我们再来说影响oom_adj的第二个因素进程的调度次序。这涉及到了ActivityManagerService的复杂调度我们下次再来看吧。呵呵。Seeyou next time