Chipset: MSM8X25Q
Codebase: Android4.1
Kernel: 3.4.0
Lowmemory killer是android基于oom killer做了改进。两者区别:
Oom killer: 当系统内存不足时,会根据当前进程的内存使用状况以及oom score来Kill掉某个进程。
Low memorykiller: 会周期性的检查系统内存状况,当系统内存小于其设定的返回时,根据 oom score和当前rss占用内存情况来杀掉进程。
两者大同小异,不过lowmemory killer概念更简单,直接看代码吧。
文件路径:android\kernel\drivers\staging\android\Lowmemorykiller.c
static int __init lowmem_init(void) { /*通过此接口注册之后,系统在内存回收释放时,kswap内核线程会遍历 Shrinker链表,并调用通过此接口注册的shrink函数。*/ register_shrinker(&lowmem_shrinker); return 0; } static struct shrinker lowmem_shrinker = { .shrink = lowmem_shrink, //核心函数在此! .seeks = DEFAULT_SEEKS * 16 };
在说核心函数之前,先了解下lowmemory killer的基础。
它利用lowmem_adj和lowmem_minfree这两个数组来作为评判当前内存不足的标准。如,当前系统空闲内存是63M时,比owmem_minfree[3]小,那么就会选择比lowmem_adj[3]的oom score adj大的进程中找到一个oom score adj最大的将其杀掉,当两个进程的oom score adj一样时,会选择内存占用最多杀掉!数组其他部分以此类推。
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;
static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc) { struct task_struct *tsk; struct task_struct *selected = NULL; int rem = 0; int tasksize; int i; int min_score_adj = OOM_SCORE_ADJ_MAX + 1; int selected_tasksize = 0; int selected_oom_score_adj; int array_size = ARRAY_SIZE(lowmem_adj); /*系统总空闲内存数*/ int other_free = global_page_state(NR_FREE_PAGES); /*文件和共享内存占用内存数*/ int other_file = global_page_state(NR_FILE_PAGES) - global_page_state(NR_SHMEM); /* 用户空间修改了lowmem_minfree和 lowmem_adj的情况就成立,后面再说*/ if (lowmem_adj_size < array_size) array_size = lowmem_adj_size; if (lowmem_minfree_size < array_size) array_size = lowmem_minfree_size; /*遍历当前各种等级下的情况*/ for (i = 0; i < array_size; i++) { /*系统总空闲内存或者文件占有内存数比当前设定的lowmem_minfree[i]小, 那么就取出相对应的oom score adj作为后面寻找最大oom score adj对应进程的基本 标准。*/ if (other_free < lowmem_minfree[i] && other_file < lowmem_minfree[i]) { min_score_adj = lowmem_adj[i]; break; } } if (sc->nr_to_scan > 0) lowmem_print(3, "lowmem_shrink %lu, %x, ofree %d %d, ma %d\n", sc->nr_to_scan, sc->gfp_mask, other_free, other_file, min_score_adj); rem = global_page_state(NR_ACTIVE_ANON) + global_page_state(NR_ACTIVE_FILE) + global_page_state(NR_INACTIVE_ANON) + global_page_state(NR_INACTIVE_FILE); if (sc->nr_to_scan <= 0 || min_score_adj == OOM_SCORE_ADJ_MAX + 1) { lowmem_print(5, "lowmem_shrink %lu, %x, return %d\n", sc->nr_to_scan, sc->gfp_mask, rem); return rem; } /*暂存,因为后面min_score_adj 会被覆盖。*/ selected_oom_score_adj = min_score_adj; rcu_read_lock(); for_each_process(tsk) { struct task_struct *p; int oom_score_adj; /*kernel thread不能Kill掉。*/ if (tsk->flags & PF_KTHREAD) continue; /*处于die状态的进程不管。*/ if (time_before_eq(jiffies, lowmem_deathpending_timeout)) { if (test_task_flag(tsk, TIF_MEMDIE)) { rcu_read_unlock(); return 0; } } /*有mm的thread才能操作*/ p = find_lock_task_mm(tsk); 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; } /*获得此进程的rss内存占用大小*/ tasksize = get_mm_rss(p->mm); task_unlock(p); if (tasksize <= 0) continue; /*前后两进程开始比较了*/ if (selected) { /*如果当前task的oom score比上次小,则不做处理*/ if (oom_score_adj < selected_oom_score_adj) continue; /*如果前后两个task的oom score一样,而且此task 占有 内存比上次的task小时,也不做处理。*/ if (oom_score_adj == selected_oom_score_adj && tasksize <= selected_tasksize) continue; } /*否则保存oom score和占用内存大小值*/ 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); } 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; /*发送SIGKILL信号杀死进程*/ send_sig(SIGKILL, selected, 0); 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; }
注意到代码里还有几个函数:
__module_param_call(MODULE_PARAM_PREFIX, adj, &lowmem_adj_array_ops, .arr = &__param_arr_adj, S_IRUGO | S_IWUSR, -1); static struct kernel_param_ops lowmem_adj_array_ops = { .set = lowmem_adj_array_set, .get = lowmem_adj_array_get, .free = lowmem_adj_array_free, }; static const struct kparam_array __param_arr_adj = { .max = ARRAY_SIZE(lowmem_adj), .num = &lowmem_adj_size, .ops = ¶m_ops_int, .elemsize = sizeof(lowmem_adj[0]), .elem = lowmem_adj, };
这几个函数也比较简单,主要功能是允许用户空间修改lowmem_adj 和lowmem_minfree这两个数组,大家可自行分析。不过要注意的是数组大小最大为6!
操作这两个数组的文件在:
android\frameworks\base\services\java\com\android\server\am\ProcessList.java
lowmem_adj对应的是mOomAdj数组的值,各个宏表示不同等级的oom score adj.
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 };通过updateOomLevels函数来修改数组值:
private void updateOomLevels(int displayWidth, int displayHeight, boolean write) { // Scale buckets from avail memory: at 300MB we use the lowest values to // 700MB or more for the top values. float scaleMem = ((float)(mTotalMemMb-300))/(700-300); // Scale buckets from screen size. int minSize = 320*480; // 153600 int maxSize = 1280*800; // 1024000 230400 870400 .264 float scaleDisp = ((float)(displayWidth*displayHeight)-minSize)/(maxSize-minSize); //Slog.i("XXXXXX", "scaleDisp=" + scaleDisp + " dw=" + displayWidth + " dh=" + displayHeight); StringBuilder adjString = new StringBuilder(); StringBuilder memString = new StringBuilder(); float scale = scaleMem > scaleDisp ? scaleMem : scaleDisp; if (scale < 0) scale = 0; else if (scale > 1) scale = 1; /*分辨率的不同会影响当前设定的lowmem_minfree。*/ for (int i=0; i<mOomAdj.length; i++) { long low = mOomMinFreeLow[i]; long high = mOomMinFreeHigh[i]; mOomMinFree[i] = (long)(low + ((high-low)*scale)); if (i > 0) { adjString.append(','); memString.append(','); } adjString.append(mOomAdj[i]); memString.append((mOomMinFree[i]*1024)/PAGE_SIZE); } Slog.e("Kris", "******************************* MINFREE: " + memString); if (write) { /*写进kernel~*/ writeFile("/sys/module/lowmemorykiller/parameters/adj", adjString.toString()); writeFile("/sys/module/lowmemorykiller/parameters/minfree", memString.toString()); } // GB: 2048,3072,4096,6144,7168,8192 // HC: 8192,10240,12288,14336,16384,20480 } // 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[] { 32768, 40960, 49152, 57344, 65536, 81920 };
2013/04/27