标签:lkm zram ksm android linux android4.4
使用安卓的朋友可能会遇到过这样的问题,就是某个应用正在使用,突然它被关闭了,或者打开某个应用,然后它就退出了,其实这背后就是LMK(Low Memory Killer)在起作用,所有形象地称之为幽灵刽子手。
1.版本平台
2.概念
3.核心结构及调用
4.总结
前文已经介绍过,LMK是定时扫描系统中的内存,当系统内存少于某个阀门值的时候,就会选择性的去释放一些内存(杀死进程),这就是你看到当前的程序突然退出的原因,可能有人会问,它系统怎么不做的人性化点,检测到我在使用,不要杀我使用的程序啊,去杀别的啊,这个我们后面慢慢道来~~
static int lowmem_adj[6] = {
0,
1,
6,
12,
};
static int lowmem_adj_size = 4;static int lowmem_minfree[6] = {
3 * 512, /* 6MB */
2 * 1024, /* 8MB */
4 * 1024, /* 16MB */
16 * 1024, /* 64MB */
};
static int lowmem_minfree_size = 4;这两个数据结构是仅仅相互关联的,那么他们是怎么相互协作的工作的呢?举个列子: p = find_lock_task_mm(tsk); /*有mm的thread才能操作*/
if (!p)
continue;
/*得到task对应的oom_score_adj*/
oom_score_adj = p->signal->oom_score_adj;
/*比当前的基本标准小就忽略。*/
if (oom_score_adj < min_score_adj) {
task_unlock(p);
continue;
}首先会扫描进程列表,查看当前进程是否有mm,只有有mm的进程才能执行以下操作,如果找到了就获得当前进程的oom_score_adj的值(即进程的adj的值),然后判断当前进程的adj值是不是比基准值小(要找到比基准值大的,且是最大的进程杀死,不要忘记前面刚说过哦~)/*获得此进程的rss内存占用大小*/ tasksize = get_mm_rss(p->mm); task_unlock(p); if (tasksize <= 0) continue;如果找到一个比基准值大的,那么记录它的内存大小,以备后面遇到两个adj值一样大小的进程可以比较谁内存占据的多就杀死谁。
if (selected) {
/*如果当前task的oom score比上次小,则不做处理*/
if (oom_score_adj < selected_oom_score_adj)
continue;/*如果前后两个task的oom score一样,而且此task 占有 <span style="white-space:pre"> </span>内存比上次的task小时,也不做处理。*/ if (oom_score_adj == selected_oom_score_adj && tasksize <= selected_tasksize) continue; }下面的问题就是最简单的问题,两两比较找到一个链表中adj最大的值,如果adj相同,找到占用内存tasksize最大的值,这样就会选择出要杀死的进程是谁了,接着往下看:
selected = p; selected_tasksize = tasksize; selected_oom_score_adj = oom_score_adj; lowmem_print(2, "select %d (%s), adj %d, size %d, to kill\n", p->pid, p->comm, oom_score_adj, tasksize); }这段代码就是更新selected的值,以便下一次比较,时刻保持selected中的adj值是最大的,并且它的占用内存是最大的,那当然因为下面我要杀死它释放内存了~~
if (selected) {
lowmem_print(1, "send sigkill to %d (%s), adj %d, size %d\n",
selected->pid, selected->comm,
selected_oom_score_adj, selected_tasksize);
lowmem_deathpending_timeout = jiffies + HZ;
send_sig(SIGKILL, selected, 0); /*发送SIGKILL信号杀死进程*/
set_tsk_thread_flag(selected, TIF_MEMDIE);
rem -= selected_tasksize;
}
lowmem_print(4, "lowmem_shrink %lu, %x, return %d\n",
sc->nr_to_scan, sc->gfp_mask, rem);
rcu_read_unlock();
return rem;
}看到了没,最终就是调用了SIGKILL这个信号让Linux内核去杀死进程的,借刀杀人,此法还是极好的。private final int[] mOomAdj = new int[] {
FOREGROUND_APP_ADJ, VISIBLE_APP_ADJ, PERCEPTIBLE_APP_ADJ,
BACKUP_APP_ADJ, HIDDEN_APP_MIN_ADJ, HIDDEN_APP_MAX_ADJ
}; // These are the low-end OOM level limits. This is appropriate for an
// HVGA or smaller phone with less than 512MB. Values are in KB.
private final long[] mOomMinFreeLow = new long[] {
8192, 12288, 16384,
24576, 28672, 32768
};
// These are the high-end OOM level limits. This is appropriate for a
// 1280x800 or larger screen with around 1GB RAM. Values are in KB.
private final long[] mOomMinFreeHigh = new long[] {
49152, 61440, 73728,
86016, 98304, 122880
};
// The actual OOM killer memory levels we are using.
private final long[] mOomMinFree = new long[mOomAdj.length];最终通过某个运算,将oOmMinFreeLow和mOomMinFreeHigh经过运算,最后得出的值存入mOomMinFree中,而如何计算这个值,是根据当前屏幕的分辨率和内存大小来,从英文注释中可以看出。 for (int i=0; i<mOomAdj.length; i++) {
long low = mOomMinFreeLow[i];
long high = mOomMinFreeHigh[i];
mOomMinFree[i] = (long)(low + ((high-low)*scale));
}
scale的值根据内存和分辨率的情况来确定,它只有两个值要不是0,要不是1,后面还有一些容错运算,然后最后来确定mOomMinFree的值,是不是感觉很繁琐?是的,我也感觉很繁琐! for (int i=0; i<mOomAdj.length; i++) {
if (i > 0) {
adjString.append(',');
memString.append(',');
}
adjString.append(mOomAdj[i]);
memString.append((mOomMinFree[i]*1024)/PAGE_SIZE);
}
。。。。。 //此处省略一些代码
//Slog.i("XXXXXXX", "******************************* MINFREE: " + memString);
if (write) {
writeFile("/sys/module/lowmemorykiller/parameters/adj", adjString.toString());
writeFile("/sys/module/lowmemorykiller/parameters/minfree", memString.toString());
SystemProperties.set("sys.sysctl.extra_free_kbytes", Integer.toString(reserve));
}
// GB: 2048,3072,4096,6144,7168,8192
// HC: 8192,10240,12288,14336,16384,20480
最终,等待更新快结束的时候,它把值写入到系统中,所以可以在节点/sys/module/lowmemorykiller/parameters/adj
和 minfree中查询到当前的阀门值。标签:lkm zram ksm android linux android4.4
原文地址:http://blog.csdn.net/memoryjs/article/details/39048947