在android中,进程这个概念被淡化了,我们知道Android的每一个应用都是运行在一个独立的DVM中,他们之间互不影响;应用退出之后,并没有立马杀死进程,进程依然停留在内存中,这么做的目的是为了提高下次启动时的速度。而在Android中管理进程的模块是AMS,主要有LRU weight,OOM adj,Low Memory Killer共同来完成进程的管理。
1 LRU weight
LRU(最近最少使用)weight 主要用来衡量LRU的权重,在android进程启动之后,会以ProcessRecord类型的方式创建一个实例,保存到AMS的mLruProcesses变量中,mLurProcesses会以LRU的顺序来存储进程信息。当有一下情况时会更新mLruProcesses:
1.应用程序异常退出
2.调用AMS显式杀死进程
3.启动和调度四大组件
这里以启动和调度四大组件为例,它最终会调用AMS的updateLruProcessLock方法:
- final void updateLruProcessLocked(ProcessRecord app,
- boolean oomAdj, boolean updateActivityTime) {
- mLruSeq++;//lru序号加一
- updateLruProcessInternalLocked(app, oomAdj, updateActivityTime, 0);
- }
先将LRU序号加一,用于标记一次更新LRU的操作,然后调用updateLruProcessInternalLocked:
- private final void updateLruProcessInternalLocked(ProcessRecord app,
- boolean oomAdj, boolean updateActivityTime, int bestPos) {
- // put it on the LRU to keep track of when it should be exited.
- int lrui = mLruProcesses.indexOf(app);
- if (lrui >= 0) mLruProcesses.remove(lrui);
- int i = mLruProcesses.size()-1;
- int skipTop = 0;
- app.lruSeq = mLruSeq;
- // compute the new weight for this process.
- if (updateActivityTime) {
- app.lastActivityTime = SystemClock.uptimeMillis();
- }
- if (app.activities.size() > 0) {
- // If this process has activities, we more strongly want to keep
- // it around.
- app.lruWeight = app.lastActivityTime;
- } else if (app.pubProviders.size() > 0) {
- // If this process contains content providers, we want to keep
- // it a little more strongly.
- app.lruWeight = app.lastActivityTime - ProcessList.CONTENT_APP_IDLE_OFFSET;
- // Also don't let it kick out the first few "real" hidden processes.
- skipTop = ProcessList.MIN_HIDDEN_APPS;
- } else {
- // If this process doesn't have activities, we less strongly
- // want to keep it around, and generally want to avoid getting
- // in front of any very recently used activities.
- app.lruWeight = app.lastActivityTime - ProcessList.EMPTY_APP_IDLE_OFFSET;
- // Also don't let it kick out the first few "real" hidden processes.
- skipTop = ProcessList.MIN_HIDDEN_APPS;
- }
- while (i >= 0) {
- ProcessRecord p = mLruProcesses.get(i);
- // If this app shouldn't be in front of the first N background
- // apps, then skip over that many that are currently hidden.
- if (skipTop > 0 && p.setAdj >= ProcessList.HIDDEN_APP_MIN_ADJ) {
- skipTop--;
- }
- if (p.lruWeight <= app.lruWeight || i < bestPos) {
- mLruProcesses.add(i+1, app);//添加到mLruProcesses合适的位置
- break;
- }
- i--;
- }
- if (i < 0) {
- mLruProcesses.add(0, app);
- }
- // 如果这个进程之后总有cotent provider或者Service,重新计算
- // If the app is currently using a content provider or service,
- // bump those processes as well.
- if (app.connections.size() > 0) {
- for (ConnectionRecord cr : app.connections) {
- if (cr.binding != null && cr.binding.service != null
- && cr.binding.service.app != null
- && cr.binding.service.app.lruSeq != mLruSeq) {
- updateLruProcessInternalLocked(cr.binding.service.app, oomAdj,updateActivityTime, i+1);
- }
- }
- }
- if (app.conProviders.size() > 0) {
- for (ContentProviderRecord cpr : app.conProviders.keySet()) {
- if (cpr.proc != null && cpr.proc.lruSeq != mLruSeq) {
- updateLruProcessInternalLocked(cpr.proc, oomAdj,
- updateActivityTime, i+1);
- }
- }
- }
- if (oomAdj) {
- updateOomAdjLocked();调用updateOomAdjLocked 更新oom adj值
- }
- }
这个函数主要作用
1.为该进程计算LRU序列号和LRU weight
2.根据计算出来的LRU weight,将该进程信息插入到mLRUProcesses合适的位置之中
3.如果该进程之中有content provider或者service,重新计算LRU weight
4.判断是否需要调用updateOomAdjLocked函数来更新oom adj的值
到此为止updateLruProcessLocked结束,可以看出,这个函数只是调整进程的LRU weight和在mLruProcesses中的位置,并没有直接参与进程的管理,真正参与进程管理的是updateOomAdjLocked函数,这个函数用来更新oom adj的值,这个值影响着进程的回收
2 OOM adj
OOM adj 定义了一系列的OOM的调整级别,从-17到15。在Low Memory Killer机制中已经介绍过,这里看一下Android中定义了13个调整级别,在ProcessList文件中
- class ProcessList {
- // OOM adjustments for processes in various states:
- // This is a process without anything currently running in it. Definitely
- // the first to go! Value set in system/rootdir/init.rc on startup.
- // This value is initalized in the constructor, careful when refering to
- // this static variable externally.
- static final int EMPTY_APP_ADJ = 15;
- // This is a process only hosting activities that are not visible,
- // so it can be killed without any disruption. Value set in
- // system/rootdir/init.rc on startup.
- static final int HIDDEN_APP_MAX_ADJ = 15;
- static int HIDDEN_APP_MIN_ADJ = 7;
- // This is a process holding the home application -- we want to try
- // avoiding killing it, even if it would normally be in the background,
- // because the user interacts with it so much.
- static final int HOME_APP_ADJ = 6;
- // This is a process holding a secondary server -- killing it will not
- // have much of an impact as far as the user is concerned. Value set in
- // system/rootdir/init.rc on startup.
- static final int SECONDARY_SERVER_ADJ = 5;
- // This is a process currently hosting a backup operation. Killing it
- // is not entirely fatal but is generally a bad idea.
- static final int BACKUP_APP_ADJ = 4;
- // This is a process with a heavy-weight application. It is in the
- // background, but we want to try to avoid killing it. Value set in
- // system/rootdir/init.rc on startup.
- static final int HEAVY_WEIGHT_APP_ADJ = 3;
- // This is a process only hosting components that are perceptible to the
- // user, and we really want to avoid killing them, but they are not
- // immediately visible. An example is background music playback. Value set in
- // system/rootdir/init.rc on startup.
- static final int PERCEPTIBLE_APP_ADJ = 2;
- // This is a process only hosting activities that are visible to the
- // user, so we'd prefer they don't disappear. Value set in
- // system/rootdir/init.rc on startup.
- static final int VISIBLE_APP_ADJ = 1;
- // This is the process running the current foreground app. We'd really
- // rather not kill it! Value set in system/rootdir/init.rc on startup.
- static final int FOREGROUND_APP_ADJ = 0;
- // This is a process running a core server, such as telephony. Definitely
- // don't want to kill it, but doing so is not completely fatal.
- static final int CORE_SERVER_ADJ = -12;
- // The system process runs at the default adjustment.
- static final int SYSTEM_ADJ = -16;
- .....
- }
AMS提供了函数来改变这个值:updateOomAdjLocked
- final void updateOomAdjLocked() {
- final ActivityRecord TOP_ACT = resumedAppLocked();
- final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
- if (false) {
- RuntimeException e = new RuntimeException();
- e.fillInStackTrace();
- Slog.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
- }
- mAdjSeq++;
- // Let's determine how many processes we have running vs.
- // how many slots we have for background processes; we may want
- // to put multiple processes in a slot of there are enough of
- // them.
- int numSlots = ProcessList.HIDDEN_APP_MAX_ADJ - ProcessList.HIDDEN_APP_MIN_ADJ + 1;
- int factor = (mLruProcesses.size()-4)/numSlots;
- if (factor < 1) factor = 1;
- int step = 0;
- int numHidden = 0;
- // First update the OOM adjustment for each of the
- // application processes based on their current state.
- int i = mLruProcesses.size();
- int curHiddenAdj = ProcessList.HIDDEN_APP_MIN_ADJ;
- int numBg = 0;
- while (i > 0) {
- i--;
- ProcessRecord app = mLruProcesses.get(i);
- //Slog.i(TAG, "OOM " + app + ": cur hidden=" + curHiddenAdj);
- //调用重载函数updateOomAdjLocked,更新OOM adj的值
- updateOomAdjLocked(app, curHiddenAdj, TOP_APP);
- if (curHiddenAdj < ProcessList.EMPTY_APP_ADJ
- && app.curAdj == curHiddenAdj) {
- step++;
- if (step >= factor) {
- step = 0;
- curHiddenAdj++;
- }
- }
- if (!app.killedBackground) {
- // 如果adj的值大于等于ProcessList.HIDDEN_APP_MIN_ADJ
- if (app.curAdj >= ProcessList.HIDDEN_APP_MIN_ADJ) {
- numHidden++;
- if (numHidden > mProcessLimit) {
- Slog.i(TAG, "No longer want " + app.processName
- + " (pid " + app.pid + "): hidden #" + numHidden);
- EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
- app.processName, app.setAdj, "too many background");
- app.killedBackground = true;
- Process.killProcessQuiet(app.pid);//杀死进程
- } else {
- numBg++;
- }
- } else if (app.curAdj >= ProcessList.HOME_APP_ADJ) {
- numBg++;
- }
- }
- }
- ......
- }
其中调用了重载函数updateOomAdjLocked,
具体代码如下:
- private final boolean updateOomAdjLocked(ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
- app.hiddenAdj = hiddenAdj;
- if (app.thread == null) {
- return false;
- }
- final boolean wasKeeping = app.keeping;
- boolean success = true;
- // 1调用computeOomAdjLocked方法计算oom adj的值
- computeOomAdjLocked(app, hiddenAdj, TOP_APP, false);
- if (app.curRawAdj != app.setRawAdj) {
- if (false) {
- // Removing for now. Forcing GCs is not so useful anymore
- // with Dalvik, and the new memory level hint facility is
- // better for what we need to do these days.
- if (app.curRawAdj > ProcessList.FOREGROUND_APP_ADJ
- && app.setRawAdj <= ProcessList.FOREGROUND_APP_ADJ) {
- // If this app is transitioning from foreground to
- // non-foreground, have it do a gc.
- scheduleAppGcLocked(app);
- } else if (app.curRawAdj >= ProcessList.HIDDEN_APP_MIN_ADJ
- && app.setRawAdj < ProcessList.HIDDEN_APP_MIN_ADJ) {
- // Likewise do a gc when an app is moving in to the
- // background (such as a service stopping).
- scheduleAppGcLocked(app);
- }
- }
- if (wasKeeping && !app.keeping) {
- // This app is no longer something we want to keep. Note
- // its current wake lock time to later know to kill it if
- // it is not behaving well.
- BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
- synchronized (stats) {
- app.lastWakeTime = stats.getProcessWakeTime(app.info.uid,
- app.pid, SystemClock.elapsedRealtime());
- }
- app.lastCpuTime = app.curCpuTime;
- }
- app.setRawAdj = app.curRawAdj;
- }
- if (app.curAdj != app.setAdj) {
- // 2 调用setOomAdj来修改进程的oom adj的值
- if (Process.setOomAdj(app.pid, app.curAdj)) {
- if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(
- TAG, "Set app " + app.processName +
- " oom adj to " + app.curAdj + " because " + app.adjType);
- app.setAdj = app.curAdj;
- } else {
- success = false;
- Slog.w(TAG, "Failed setting oom adj of " + app + " to " + app.curAdj);
- }
- }
- if (app.setSchedGroup != app.curSchedGroup) {
- app.setSchedGroup = app.curSchedGroup;
- if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG,
- "Setting process group of " + app.processName
- + " to " + app.curSchedGroup);
- if (app.waitingToKill != null &&
- app.setSchedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE) {
- Slog.i(TAG, "Killing " + app.toShortString() + ": " + app.waitingToKill);
- EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
- app.processName, app.setAdj, app.waitingToKill);
- // 3 调用killProcessQuiet杀死进程
- Process.killProcessQuiet(app.pid);
- success = false;
- } else {
- if (true) {
- long oldId = Binder.clearCallingIdentity();
- try {
- // 4调用setProcessGroup修改进程的调度组
- Process.setProcessGroup(app.pid, app.curSchedGroup);
- } catch (Exception e) {
- Slog.w(TAG, "Failed setting process group of " + app.pid
- + " to " + app.curSchedGroup);
- e.printStackTrace();
- } finally {
- Binder.restoreCallingIdentity(oldId);
- }
- } else {
- if (app.thread != null) {
- try {
- app.thread.setSchedulingGroup(app.curSchedGroup);
- } catch (RemoteException e) {
- }
- }
- }
- }
- }
- return success;
- }
函数updateOomAdjLocked,更新OOM adj的值,这一部分的主要工作有:
1.调用computeOomAdjLocked方法计算oom adj的值,这个函数比较复杂,通过一系列的运算,计算出oom adj的值
2.调用setOomAdj来修改进程的oom adj的值,这个函数就是向进程的/proc/<pid>/oom_adj文件写入计算出来的oom adj值
3.调用killProcessQuiet杀死进程
4.调用setProcessGroup修改进程的调度组
这里主要看第三步killProcessQuiet,这个函数在Process.java文件中:
- public static final void killProcessQuiet(int pid) {
- sendSignalQuiet(pid, SIGNAL_KILL);
- }
调用了 sendSignalQuiet函数,这是一个native函数:
- public static final native void sendSignalQuiet(int pid, int signal);
对应的实现在android_util_Process.cpp文件中:
- void android_os_Process_sendSignalQuiet(JNIEnv* env, jobject clazz, jint pid, jint sig)
- {
- if (pid > 0) {
- kill(pid, sig);//杀死进程
- }
- }
到此为止进程杀死了,这种方式是直接杀死进程的方式,同样android还提供了一个被动杀死进程的机制 Low Memory Killer机制
3 Low Memory Killer机制
这一机制的主要思想就是定义不同的oom adj级别,并为每一个级别指定最小剩余阈值。当内存中可用内存小于该阈值时,就杀死所有等于或者大于该级别的进程,这部分参看 Low Memory Killer机制
447

被折叠的 条评论
为什么被折叠?



