Android LowMemoryKiller机制

1,795 阅读7分钟

LowMemoryKiller机制

Android的LowMemoryKiller(lmk)机制是一种内存回收机制,它根据当前系统的内存阈值以及进程的优先级来决定杀掉哪些进程。LowMemoryKiller会周期性的检查当前系统的可用内存,当系统剩余的可用内存较低时,便会触发进程杀掉进程的策略。它根据不同的内存阈值来决定杀掉相应优先级的进程。

Android的LowMemoryKiller机制是基于Linux的OOM Killer机制修改而来,在KK版本中,LMK机制和策略都是在内核空间驱动中实现的,在L版本中LowMemeoryKiller做了一些调整改动,但总体的思想还是一样的。

Kernel层的实现

// kernel/drivers/staging/android/lowmemorykiller.c
static uint32_t lowmem_debug_level = 2;
//低内存阈值对应的优先级,这个值越低就优先级越高
static int lowmem_adj[6] = {
	0,
	1,
	6,
	12,
};
static int lowmem_adj_size = 4;
//低内存的阈值
static size_t lowmem_minfree[6] = {
	3 * 512,	/* 6MB */
	2 * 1024,	/* 8MB */
	4 * 1024,	/* 16MB */
	16 * 1024,	/* 64MB */
};
//当系统可用的内存小于某一低内存阈值时,lowmemoryKiller会去比对应优先级低的进程,
//比如:当系统可用内存低于64MB时会去杀掉优先级低于12的进程
static int lowmem_minfree_size = 4;
……

在lowmemorykiller中定义了两个数组分别是lowmem_infree和lowmem_adj,它们分别是用来描述当前系统的低内存阈值以及低内存阈值对应的进程优先级,lmk正是基于这个优先级来决定是否杀掉当前进程。

static int __init lowmem_init(void)
{
	task_free_register(&task_nb);
	register_shrinker(&lowmem_shrinker);
	return 0;
}

static void __exit lowmem_exit(void)
{
	unregister_shrinker(&lowmem_shrinker);
	task_free_unregister(&task_nb);
}

module_init(lowmem_init);
module_exit(lowmem_exit);

lmk将自己的lowmem_shrink方法诸恶到系统的内存检测模块中,作用就是在内存不足的时候可以被回调,register_shrinker函数是一属于另一个内存管理模块的函数。

//内存检测模块检测到内存不足时调用,在这个方法里面会去查找低优先级的进程
static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
{
	struct task_struct *p;
	struct task_struct *selected = NULL;
	int rem = 0;
	int tasksize;
	int i;
	int min_adj = OOM_ADJUST_MAX + 1;//初始化为最低优先级
	int selected_tasksize = 0;
	int selected_oom_adj;
	int array_size = ARRAY_SIZE(lowmem_adj);
	//1. 获取剩余内存大小
	int other_free = global_page_state(NR_FREE_PAGES);
	int other_file = global_page_state(NR_FILE_PAGES) -
						global_page_state(NR_SHMEM);

	
	if (lowmem_deathpending &&
	    time_before_eq(jiffies, lowmem_deathpending_timeout))
		return 0;

	//调整两个数组的大小描述
	if (lowmem_adj_size < array_size)
		array_size = lowmem_adj_size;//4
	if (lowmem_minfree_size < array_size)
		array_size = lowmem_minfree_size;//4

	//2. 找到当前的内存对应的阈值
	for (i = 0; i < array_size; i++) {
		if (other_free < lowmem_minfree[i] &&
		    other_file < lowmem_minfree[i]) {
			min_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_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_adj == OOM_ADJUST_MAX + 1) {
		lowmem_print(5, "lowmem_shrink %lu, %x, return %d\n",
			     sc->nr_to_scan, sc->gfp_mask, rem);
		return rem;
	}
	//这里的min_adj即我们计算得到优先级,低于该优先级的进程都有可能被杀掉
	selected_oom_adj = min_adj;
	//3. 找到优先级低于这个阈值的进程,并杀死
	read_lock(&tasklist_lock);
	for_each_process(p) {
		struct mm_struct *mm;
		struct signal_struct *sig;
		int oom_adj;

		task_lock(p);
		mm = p->mm;
		sig = p->signal;
		if (!mm || !sig) {
			task_unlock(p);
			continue;
		}
		oom_adj = sig->oom_adj;
		if (oom_adj < min_adj) {
			task_unlock(p);
			continue;
		}
		tasksize = get_mm_rss(mm);
		task_unlock(p);
		if (tasksize <= 0)
			continue;
		if (selected) {
			if (oom_adj < selected_oom_adj)//优先级大于selected_oom_adj的进程 就不做处理
				continue;
			if (oom_adj == selected_oom_adj &&
			    tasksize <= selected_tasksize)
				continue;
		}
		selected = p;
		selected_tasksize = tasksize;
		selected_oom_adj = oom_adj;
		lowmem_print(2, "select %d (%s), adj %d, size %d, to kill\n",
			     p->pid, p->comm, oom_adj, tasksize);
	}
	if (selected) {
		lowmem_print(1, "send sigkill to %d (%s), adj %d, size %d\n",
			     selected->pid, selected->comm,
			     selected_oom_adj, selected_tasksize);
		lowmem_deathpending = selected;
		lowmem_deathpending_timeout = jiffies + HZ;
		force_sig(SIGKILL, selected);//杀死这个进程
		rem -= selected_tasksize;
	}
	lowmem_print(4, "lowmem_shrink %lu, %x, return %d\n",
		     sc->nr_to_scan, sc->gfp_mask, rem);
	read_unlock(&tasklist_lock);
	return rem;
}

lowmem_shrink是lmk的核心处理方法,它的逻辑比较简单,首先通过global_page_state得到当前系统可用的空闲内存大小,随后根据该空闲内存的大小找到相应的内存阈值对应的进程优先级并将其赋值给selected_oom_adj,低于该优先级的进程都有可能被lmk杀掉。for_each_process遍历进程列表,然后找出进程优先级最低的进程通过fore_sig选择杀死进程。

应用恢复机制

Android应用的恢复是通过AMS来进行的。那么AMS恢复的过程是如何的呢?AMS是怎么知道应用被杀掉的?

LowMemoryKiller杀死应用后并不会通知应用层,也不通知AMS,但是我们知道AMS和应用端的通信是基于Binder机制的,别忘了Binder是由卟告功能的,Binder Client通过linkToDeath注册接收该卟告。当Binder Server端死亡后会通过它来告知客户端。这里的Binder Server就是IApplicationThread,这个对象是在ActivityThread中创建的,用于AMS和客户端进行通信的,AMS就是通过它来告诉Activity执行一系列的回调方法。

//应用创建完application后attach IApplicationThread 到AMS
@Override
public final void attachApplication(IApplicationThread thread) {
    synchronized (this) {
        int callingPid = Binder.getCallingPid();
        final long origId = Binder.clearCallingIdentity();
        attachApplicationLocked(thread, callingPid);
        Binder.restoreCallingIdentity(origId);
    }
}

private final boolean attachApplicationLocked(IApplicationThread thread,
    int pid) {
    ...
    try {
        AppDeathRecipient adr = new AppDeathRecipient(
                app, pid, thread);
        thread.asBinder().linkToDeath(adr, 0);//应用端binder的卟告 这样当应用被异常杀死后AMS可以得知
        app.deathRecipient = adr;
    } catch (RemoteException e) {
        app.resetPackageList(mProcessStats);
        startProcessLocked(app, "link fail", processName);
        return false;
    }
    ...
}

//应用端死亡卟告接收者 它是通过binder来实现的,binder服务端在异常终止时客户端会收到一份卟告
private final class AppDeathRecipient implements IBinder.DeathRecipient {
    final ProcessRecord mApp;
    final int mPid;
    final IApplicationThread mAppThread;//这即是客户端的Binder实体,应用端被杀死后,binder驱动会发送该binder实体的卟告

    AppDeathRecipient(ProcessRecord app, int pid,
            IApplicationThread thread) {
        if (localLOGV) Slog.v(
            TAG, "New death recipient " + this
            + " for thread " + thread.asBinder());
        mApp = app;
        mPid = pid;
        mAppThread = thread;
    }
    //卟告的回调
    @Override
    public void binderDied() {
        if (localLOGV) Slog.v(
            TAG, "Death received in " + this
            + " for thread " + mAppThread.asBinder());
        synchronized(ActivityManagerService.this) {
            appDiedLocked(mApp, mPid, mAppThread);//通知AMS应用端进程死亡
        }
    }
}

在应用创建后就AMS通过attachApplication调用attachApplicationLocked来注册Binder服务的卟告回调。它是一个AppDeathRecipient继承自IBinder.DeathRecipient,当服务端也就是应用端被杀掉后,会通过binderDied来通知AMS,这时候AMS通过appDiedLocked方法来处理应用被杀的逻辑。我们看看AMS这时候是如何处理的。

//app被后台杀死后会通过此方法通知AMS ,这是由binder机制保证的
final void appDiedLocked(ProcessRecord app, int pid,
        IApplicationThread thread) {
    ...
    // Clean up already done if the process has been re-started.
    if (app.pid == pid && app.thread != null &&
            app.thread.asBinder() == thread.asBinder()) {
        boolean doLowMem = app.instrumentationClass == null;
        boolean doOomAdj = doLowMem;
        if (!app.killedByAm) {
            mAllowLowerMemLevel = true;
            if("android.process.media".equals(app.processName))
            {
                SystemProperties.set("service.media_oncekilled", "true");
            }
        } else {
            mAllowLowerMemLevel = false;
            doLowMem = false;
        }

        handleAppDiedLocked(app, false, true);//处理app died的情况

        if (doOomAdj) {
            updateOomAdjLocked();
        }
        if (doLowMem) {//内存较低引起的要通知其他app low memory
            doLowMemReportIfNeededLocked(app);
        }
    }
    ...
}

在appDiedLocked中进一步通过handleAppDiedLocked来处理。

private final void handleAppDiedLocked(ProcessRecord app,
        boolean restarting, boolean allowRestart) {
    //清理一些关于该应用的信息
    cleanUpApplicationRecordLocked(app, restarting, allowRestart, -1);
    if (!restarting) {
        removeLruProcessLocked(app);
    }

    if (mProfileProc == app) {
        clearProfilerLocked();
    }

    // Remove this application's activities from active lists.
    boolean hasVisibleActivities = mStackSupervisor.handleAppDiedLocked(app);

    app.activities.clear();

    if (app.instrumentationClass != null) {
        Slog.w(TAG, "Crash of app " + app.processName
                + " running instrumentation " + app.instrumentationClass);
        Bundle info = new Bundle();
        info.putString("shortMsg", "Process crashed.");
        finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
    }

    if (!restarting) {
        if (!mStackSupervisor.resumeTopActivitiesLocked()) {
            if (hasVisibleActivities) {
                mStackSupervisor.ensureActivitiesVisibleLocked(null, 0);
            }
        }
    }
}

handleAppDiedLocked主要负责以下事情:

  1. 负责清理一些Providers,receivers,service之类的信息
  2. 从活动的Activity列表移除该应用的Activities
  3. 通过resumeTopActivitiesLocked重建进程
private final void cleanUpApplicationRecordLocked(ProcessRecord app,
        boolean restarting, boolean allowRestart, int index) {
    ...
    mServices.killServicesLocked(app, allowRestart);
    
    boolean restart = false;
    //清理已经发布的provoider
    // Remove published content providers.
    for (int i=app.pubProviders.size()-1; i>=0; i--) {
        ContentProviderRecord cpr = app.pubProviders.valueAt(i);
        final boolean always = app.bad || !allowRestart;
        if (removeDyingProviderLocked(app, cpr, always) || always) {
            // We left the provider in the launching list, need to
            // restart it.
            restart = true;
        }

        cpr.provider = null;
        cpr.proc = null;
    }
    app.pubProviders.clear();

    // Take care of any launching providers waiting for this process.
    if (checkAppInLaunchingProvidersLocked(app, false)) {
        restart = true;
    }
    
    // Unregister from connected content providers.
    if (!app.conProviders.isEmpty()) {
        for (int i=0; i<app.conProviders.size(); i++) {
            ContentProviderConnection conn = app.conProviders.get(i);
            conn.provider.connections.remove(conn);
        }
        app.conProviders.clear();
    }
    ...
    skipCurrentReceiverLocked(app);
    //解注册所有的receiver
    // Unregister any receivers.
    for (int i=app.receivers.size()-1; i>=0; i--) {
        removeReceiverLocked(app.receivers.valueAt(i));
    }
    app.receivers.clear();
    ...
    if (restart && !app.isolated) {
        // We have components that still need to be running in the
        // process, so re-launch it.
        mProcessNames.put(app.processName, app.uid, app);
        startProcessLocked(app, "restart", app.processName);
    } 
    ...
}

cleanUpApplicationRecordLocked负责清理应用的service,provider以及receiver的信息,并根据需要重启该进程。

boolean handleAppDiedLocked(ProcessRecord app) {
    boolean hasVisibleActivities = false;
    for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
        hasVisibleActivities |= mStacks.get(stackNdx).handleAppDiedLocked(app);
    }
    return hasVisibleActivities;
}
boolean handleAppDiedLocked(ProcessRecord app) {
    if (mPausingActivity != null && mPausingActivity.app == app) {
        mPausingActivity = null;
    }
    if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
        mLastPausedActivity = null;
        mLastNoHistoryActivity = null;
    }

    return removeHistoryRecordsForAppLocked(app);
}

boolean removeHistoryRecordsForAppLocked(ProcessRecord app) {
    removeHistoryRecordsForAppLocked(mLRUActivities, app, "mLRUActivities");
    removeHistoryRecordsForAppLocked(mStackSupervisor.mStoppingActivities, app,
            "mStoppingActivities");
    removeHistoryRecordsForAppLocked(mStackSupervisor.mGoingToSleepActivities, app,
            "mGoingToSleepActivities");
    removeHistoryRecordsForAppLocked(mStackSupervisor.mWaitingVisibleActivities, app,
            "mWaitingVisibleActivities");
    removeHistoryRecordsForAppLocked(mStackSupervisor.mFinishingActivities, app,
            "mFinishingActivities");
    // Clean out the history list.
    int i = numActivities();
     for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
            final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
                final ActivityRecord r = activities.get(activityNdx);
                --i;
                 if (r.app == app) {
                    boolean remove;
                    if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
                        // Don't currently have state for the activity, or
                        // it is finishing -- always remove it.
                        remove = true;
                    } else if (r.launchCount > 2 &&
                            r.lastLaunchTime > (SystemClock.uptimeMillis()-60000)) {
                        // We have launched this activity too many times since it was
                        // able to run, so give up and remove it.
                        remove = true;
                    } else {
                        // The process may be gone, but the activity lives on!
                        remove = false;
                    }
                    if (remove) {
                        if (!r.finishing) {
                            if (r.state == ActivityState.RESUMED) {
                                mService.updateUsageStats(r, false);
                            }
                        }
                        removeActivityFromHistoryLocked(r);
                    }else{
                        if (r.visible) {
                            hasVisibleActivities = true;
                        }
                        r.app = null;//将app 置null
                        r.nowVisible = false;
                        if (!r.haveState) {
                            r.icicle = null;
                        }
                    }
                    cleanUpActivityLocked(r, true, true);
                 }
            }
     }
}

removeHistoryRecordsForAppLocked首先从mLRUActivities,mStoppingActivities,mGoingToSleepActivities等多个列表中移除app相关的activity,随后遍历ActivityStack找到和app相关的activity,根据不同的情况标记activity是否应该从历史列表中移除该activity,如果需要的话就调用removeActivityFromHistoryLocked,如果不需要就将r.app置为null。这样在AMS启动activity时就知道该应用的进程需要重建了。

final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {
    ...
    if (next.app != null && next.app.thread != null) {

    }else {
        //1.要启动的activity还未创建过进程
        //2.app或者activity被异常杀死过,需要重新启动
        // Whoops, need to restart this activity!
        if (!next.hasBeenLaunched) {
            next.hasBeenLaunched = true;
        } 
        mStackSupervisor.startSpecificActivityLocked(next, true, true);
    }
}

void startSpecificActivityLocked(ActivityRecord r,
            boolean andResume, boolean checkConfig) {
    if (app != null && app.thread != null) {
        ...
    }
    ...
     mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                "activity", r.intent.getComponent(), false, false, true);
}

r.app被置位null后,AMS会去重建该activity对应的进程。