LowMemoryKiller是Android 系统在Linux kernel的OOMKiller基础上打的一个补丁。OOMKiller在kernel 无法再分配内存的时候,寻找一个得分最高的进程来杀掉。LowMemoryKiller则提早一步,经过把剩余内存划分红不一样的级别,内存在消耗的过程当中,触发不一样的级别,杀死相应的app进程。在触发OOMKiller前,大量缓存的app进程已经被杀死掉了。java
先简单说一下OOMKiller。android
咱们查看任一进程的proc信息(如:/proc/1), 都会看到如下三个参数:算法
所以,用户设置oom_adj后,kernel会转换并更新该进程实际的oom_score_adj值,它们的换算关系是:数组
#define OOM_DISABLE (-17) #define OOM_SCORE_ADJ_MAX 1000 oom_score_adj = (oom_adj * OOM_SCORE_ADJ_MAX) / -OOM_DISABLE; oom_adj = (oom_score_adj * - OOM_DISABLE) / OOM_SCORE_ADJ_MAX;
从上面能够看到,这个算法是有损的,因此,有时候会发现读出的oom_adj的值同设置得不同了。如,设置oomajd=13, 那么 oom_score_adj=764,再次读oom_adj, 764 * 17 / 1000 == 12了。缓存
当内存耗尽的时候,OOMKiller会调用 out_of_memory()来select_bad_process(), oom_score最大的值就是那个将要被杀死的bad process。 oom_badness()以oom_score_adj做为基础值,根据是否为管理员进程,占用的内存状况,来计算出最终的oom_score值,分值越高,越容易被杀死。app
OOMKiller相应的源码文件:socket
/fs/proc/base.c /mm/oom_kill.c
在Android系统里面,当app的状态发生变化,如:建立,收到广播,唤醒,放入后台等, ActivityManagerService的updateOomAdjLocked() 会computeOomAdjLocked(),而后,经过applyOomAdjLocked()把app的oom_adj值写入到Linux Kernel。函数
那么AN是如何计算每一个app最终的oom_adj值的呢?工具
咱们知道oom_adj的范围是[-16, 15],AN根据app进程的特性进行了分类,不一样的类别,对应不一样的数值。网站
LowMemoryKiller注册了shrinker--Linux Kernel的一个内存管理工具,当kernel须要回收内存时,会回调LowMemoryKiller的lowmem_shrink(),它先检查kernel 剩下多少内存,根据剩下的内存数量来匹配数组 lowmem_minfree[], 找到数组索引值,而后,再使用该索引值,从 lowmem_adj[]这个数组里面就获得目标oom_adj值,最终,在大于等于该目标oom_adj的进程中,杀死拥有最大oom_adj值的进程--send_sig(SIGKILL, selected, 0) 。算法其实很简单,就是两个一维数组的映射。
static short lowmem_adj[6] = { 0, 1, 6, 12, }; static int lowmem_minfree[6] = { 3 * 512, /* 6MB */ 2 * 1024, /* 8MB */ 4 * 1024, /* 16MB */ 16 * 1024, /* 64MB */ };
如: 系统剩下的内存为 31024, 它 小于 4 1024,对应的数组索引是 2, lowmem_adj[2]对应的是 6,那么系统将在oom_adj>=6的进程中,找一个最大的oom_adj的进程,而后,杀死它释放内存。
Android在初始化的时候,会经过ProcessList::updateOomLevels()来设定上面两个数组的初始值,咱们能够经过framework的config.xml,或 /sys文件系统接口进行调整lowmem_minfree []。
/sys/module/lowmemorykiller/parameters/minfree <integer name="config_lowMemoryKillerMinFreeKbytesAbsolute">-1</integer> <integer name="config_lowMemoryKillerMinFreeKbytesAdjust">0</integer>
config_....KbytesAbsolute:非-1的状况下,是绝对值, AN使用下面算法,获得实际数组值。
for ( int i = 0 ; i < mOomAdj.length; i++) { mOomMinFree[ i ] = (int) ((float)minfree_abs * mOomMinFree[ i ] / mOomMinFree[ mOomAdj.length - 1 ] ); }
config_....KbytesAdjust: 非0状况下, 直接在每一个数组值上 += reserve_adj;
如: <integer name="config_....KbytesAdjust">-512</integer>,代表每一个数组值都减小512。
lowmem_adj[] 能够经过/sys 文件系统接口来进行调整。
/sys/module/lowmemorykiller/parameters/adj
固然了在实际上开发过程当中,也能够直接在这个函数里面打补丁,或者读取系统属性,经过属性来进行配置等等。 像MStar方案,就定义了两个属性来进行第三方的配置: ro.mstar.lmkd.minfree和ro.mstar.lmkd.adj
到这里,基本上LowMemoryKiller算是说完了,最后,简单介绍下,AN是如何把oom_adj值传给kernel的。
AN经过ProcessList:setOomAdj(),用socket与lmkd通信, lmkd经过/sys文件系统接口,把oom_adj值传递给LinuxKernel。
/sys/module/lowmemorykiller/parameters/minfree /sys/module/lowmemorykiller/parameters/adj
相关的源码文件分别在:
system/core/lmkd/ 生成 /system/bin/lmkd drivers/staging/android/lowmemorykiller.c framework/base/...../server/am/
欢迎你们来个人网站交流:般若程序蝉:prajna.top