在android中,进程这个概念被淡化了,我们知道Android的每一个应用都是运行在一个独立的DVM中,他们之间互不影响;应用退出之后,并没有立马杀死进程,进程依然停留在内存中,这么做的目的是为了提高下次启动时的速度,
Android中进程管理
。而在Android中管理进程的模块是AMS,主要有LRU weight,OOM adj,Low Memory Killer共同来完成进程的管理。1 LRU weightLRU(最近最少使用)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 adjOOM 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 ldId = 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/
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级别,并为每一个级别指定最小剩余阈值,
电脑资料
《Android中进程管理》(https://www.unjs.com)。当内存中可用内存小于该阈值时,就杀死所有等于或者大于该级别的进程,这部分参看 Low Memory Killer机制