从zygote孵化出来的进程都会记录在ActivityManagerService.mLruProcesses列表中,由ActivityManagerService进行统一管理,ActivityManagerService核心业务之一便是时时更新进程的状态,根据状态计算出进程对应的OomAdj值,这个值会传递到kernel中去,kernel有个低内存回收机制,在内存达到一定阀值时会触发清理OomAdj值高的进程,这边是Lowmemorykiller工作原理。
第一部分:进程OomAdj值的设置
这个流程中,ActivityManagerService会计算出进程的OomAdj值,然后通过Lmkd这个native进程来将OomAdj值分别写入对应进程的oom_score_adj节点去。可以通过cat /proc/%pid/oom_score_adj来查看每个进程的OomAdj值。
注意:
①OomAdj值越小表示优先级越高,越不容易被kill。
②ActivityManagerService中为进程设定的OomAdj值取值范围为-16~16,设定到oom_score_adj节点中的值是经过 OomAdj*1000/17 公式计算出来的。
③native进程OomAdj值默认为-17,也就是说native进程oom_score_adj节点中值必是-1000.
第二部分:核心调用lowmem_shrink()
这个函数主要根据当前剩余内存与lowmem_minfree来评判当前内存已经达到哪个阀值以下(每个阀值都对应一个lowmem_adj值),进而得出一个lowmem_adj基准值(只有OomAdj值大于这个lowmem_adj基准值的进程才可能被杀)。
代码在/drivers/staging/android/lowmemorykiller.c
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) - totalreserve_pages;
int other_file = global_page_state(NR_FILE_PAGES) -
global_page_state(NR_SHMEM);
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数组进行评判,找到lowmem_adj基准值赋给min_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;
}
selected_oom_score_adj = min_score_adj;
rcu_read_lock();
for_each_process(tsk) { //该for循环找出oom_score_adj值最大的进程作为目标进程(将被kill),如果最大oom_score_adj值有多个进程,那么选取rss值最大的进程为目标进程;
struct task_struct *p;
int oom_score_adj;
if (tsk->flags & PF_KTHREAD)
continue;
p = find_lock_task_mm(tsk);
if (!p)
continue;
if (test_tsk_thread_flag(p, TIF_MEMDIE) &&
time_before_eq(jiffies, lowmem_deathpending_timeout)) {
task_unlock(p);
rcu_read_unlock();
return 0;
}
oom_score_adj = p->signal->oom_score_adj;
if (oom_score_adj < min_score_adj) {
task_unlock(p);
continue;
}
tasksize = get_mm_rss(p->mm);
task_unlock(p);
if (tasksize <= 0)
continue;
if (selected) {
if (oom_score_adj < selected_oom_score_adj)
continue;
if (oom_score_adj == selected_oom_score_adj &&
tasksize <= selected_tasksize)
continue;
}
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) { //前面for循环找到一个目标进程,那么便调用send_sig()干掉它。
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);
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;
}
该函数的逻辑很简单,就是kill掉Oomadj值大的进程来回收内存。
注意:由于native进程的Oomadj值为-17,SystemServer进程的Oomadj值为-16,毫无疑问native进程不会被Lowmemorykiller干掉。
第三部分:Oomadj的计算
OomAdj的计算主要在computeOomAdjLocked()函数中完成。
private final int computeOomAdjLocked(ProcessRecord app, int cachedAdj, ProcessRecord TOP_APP,
boolean doingAll, long now) {
if (mAdjSeq == app.adjSeq) {
// This adjustment has already been computed.
return app.curRawAdj;
}
if (app.thread == null) {
app.adjSeq = mAdjSeq;
app.curSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
app.curProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
return (app.curAdj=app.curRawAdj=ProcessList.CACHED_APP_MAX_ADJ);
}
app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
app.adjSource = null;
app.adjTarget = null;
app.empty = false;
app.cached = false;
final int activitiesSize = app.activities.size();
if (app.maxAdj <= ProcessList.FOREGROUND_APP_ADJ) { //如果是常驻进程、SystemServer进程,那么该条件是满足的,对于一般进程maxAdj值为UNKNOWN_ADJ
// The max adjustment doesn't allow this app to be anything
// below foreground, so it is not worth doing work for it.
app.adjType = "fixed";
app.adjSeq = mAdjSeq;
app.curRawAdj = app.maxAdj;
app.foregroundActivities = false;
app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
app.curProcState = ActivityManager.PROCESS_STATE_PERSISTENT;
// System processes can do UI, and when they do we want to have
// them trim their memory after the user leaves the UI. To
// facilitate this, here we need to determine whether or not it
// is currently showing UI.
app.systemNoUi = true;
if (app == TOP_APP) {
app.systemNoUi = false;
} else if (activitiesSize > 0) {
for (int j = 0; j < activitiesSize; j++) {
final ActivityRecord r = app.activities.get(j);
if (r.visible) {
app.systemNoUi = false;
}
}
}
if (!app.systemNoUi) { //如果进程是当前resume activity的进程,或者有可见的activity,那么把curProcState修改成PROCESS_STATE_PERSISTENT_UI
app.curProcState = ActivityManager.PROCESS_STATE_PERSISTENT_UI;
}
return (app.curAdj=app.maxAdj);
}
app.systemNoUi = false; /*以下逻辑是计算普通进程的Oomadj值,主要计算进程的adj、schedGroup、procState、foregroundActivities四个变量*/
// Determine the importance of the process, starting with most
// important to least, and assign an appropriate OOM adjustment.
int adj;
int schedGroup;
int procState;
boolean foregroundActivities = false;
BroadcastQueue queue;
if (app == TOP_APP) { //这大段if else逻辑里面的条件是权重最高的,如果满足这些条件之一,那么几个状态值基本就确定下来了,如果都不满足,那么最后一个else会给一个初值;
// The last app on the list is the foreground app.
adj = ProcessList.FOREGROUND_APP_ADJ;
schedGroup = Process.THREAD_GROUP_DEFAULT;
app.adjType = "top-activity";
foregroundActivities &#