Jimmy Chen

A Programmer

(原创)基于Android 8.1之updateOomAdjLocked源码分析

  在lowmemorykiller的源码分析中,我们了解到在内存紧张的情况下,lmkd会根据oom的分数值,对应用进行清杀操作。上一篇主要讲lmkd驱动及lmkd守护进程的相关内容,还没有涉及到oom分数值更新的分析,所以这一篇我们分析updateOomAdjLocked方法是如何更新oom分数值的,另外分析外updateOomAdjLocked方法后,还能了解到除了lmkd因低内存杀死进程外的另一种内存清理操作。

updateOomAdjLocked分析

  updateOomAdjLocked在AMS中存在重载函数,分别是不带参数的、带一个参数的和带五个参数的,这里我们主要分析不带参数的重载函数。不带参数的重载函数内容比较多,所以这里只能分段分析

// 获取当前前台的app
final ActivityRecord TOP_ACT = resumedAppLocked();
final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
final long now = SystemClock.uptimeMillis();
final long nowElapsed = SystemClock.elapsedRealtime();
final long oldTime = now - ProcessList.MAX_EMPTY_TIME;
// 获取当前运行的进程数量
final int N = mLruProcesses.size();

// 调试用,可以不看
if (false) {
    RuntimeException e = new RuntimeException();
    e.fillInStackTrace();
    Slog.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
}

// 重置UID状态
for (int i=mActiveUids.size()-1; i>=0; i--) {
    final UidRecord uidRec = mActiveUids.valueAt(i);
    if (false && DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
            "Starting update of " + uidRec);
    uidRec.reset();
}

mStackSupervisor.rankTaskLayersIfNeeded();

mAdjSeq++;
// 存活的service进程的数量
mNewNumServiceProcs = 0;
// 存活的A service进程的数量
mNewNumAServiceProcs = 0;

  如果当前前台有进程,那么TOP_ACT和TOP_APP就代表当前前台进程,否则就代表栈顶进程。ProcessList.MAX_EMPTY_TIME;代表空进程最长存活时间,定义在ProcessList.java中,一般为30分钟。N为Lru排序的链表中的存活进程的数量。

// 获取系统当前设置的空进程上限
final int emptyProcessLimit = mConstants.CUR_MAX_EMPTY_PROCESSES;
// 获取系统当前设置的缓存进程上限
final int cachedProcessLimit = mConstants.CUR_MAX_CACHED_PROCESSES - emptyProcessLimit;

// 计算slots数量,一般CACHED_APP_MAX_ADJ一般为906,CACHED_APP_MIN_ADJ为900,所以numSlots为3 
int numSlots = (ProcessList.CACHED_APP_MAX_ADJ
        - ProcessList.CACHED_APP_MIN_ADJ + 1) / 2;

// 计算空进程数量
int numEmptyProcs = N - mNumNonCachedProcs - mNumCachedHiddenProcs;
// 空进程超过限制,将空进程数量设置为受限的数量
if (numEmptyProcs > cachedProcessLimit) {
    numEmptyProcs = cachedProcessLimit;
}

// 计算每个slot存放的空进程数量
int emptyFactor = numEmptyProcs/numSlots;
// 保证每个slot存放的空进程数量至少为1
if (emptyFactor < 1) emptyFactor = 1;
// 计算每个slot存放的缓存进程的数量
int cachedFactor = (mNumCachedHiddenProcs > 0 ? mNumCachedHiddenProcs : 1)/numSlots;
if (cachedFactor < 1) cachedFactor = 1;
int stepCached = 0;
int stepEmpty = 0;
int numCached = 0;
int numEmpty = 0;

  emptyProcessLimit代表系统空进程数量的上限,cachedProcessLimit代表的是缓存进程的数量上限,这两个进程的上限值是可以设置。接下来的代码我们先脱离updateOomAdjLocked主线,先分析emptyProcessLimit是怎么设置的。另外,numSloas计算过程中除以2是因为每个槽配置到进程包含后台进程和empty进程两种,两种进程需用不同adj值表示,所以每个槽包含两个adj值的分配空间,所以需要除以二,计算出来的numSlots值为3。其中,emptyFactor表示每个adj包含的空进程个数,而cacheFactor表示每个adj包含的cache的空进程数量。

emptyProcessLimit上限设置分析

  之前的代码中emptyProcessLimit设置为mConstants.CUR_MAX_EMPTY_PROCESSES;,而mConstants是一个ActivityManagerConstants类对象。所以可以直接查看该类的代码

// CUR_MAX_EMPTY_PROCESSES定义
public int CUR_MAX_EMPTY_PROCESSES;

// mOverrideMaxCachedProcesses初始化为-1,该值如果有做override才会被改写
// 这里假设使用系统默认,不做override
private int mOverrideMaxCachedProcesses = -1;

// MAX_CACHED_PROCESSES值可以通过系统属性进行设置,如果没有设置默认为32
public int MAX_CACHED_PROCESSES = DEFAULT_MAX_CACHED_PROCESSES;
private static final int DEFAULT_MAX_CACHED_PROCESSES =
        SystemProperties.getInt("ro.vendor.qti.sys.fw.bg_apps_limit",32);

private void updateMaxCachedProcesses() {
    // 这里判断mOverrideMaxCachedProcesses是否有做override
    // 如上面假设,这里没有做,所以CUR_MAX_CACHED_PROCESSES就等于MAX_CACHED_PROCESSES
    CUR_MAX_CACHED_PROCESSES = mOverrideMaxCachedProcesses < 0
            ? MAX_CACHED_PROCESSES : mOverrideMaxCachedProcesses;

    // computeEmptyProcessLimit方法的返回值如下面所示
    // 所以CUR_MAX_EMPTY_PROCESSES就是CUR_MAX_CACHED_PROCESSES的一般,默认为16
    CUR_MAX_EMPTY_PROCESSES = computeEmptyProcessLimit(CUR_MAX_CACHED_PROCESSES);

    final int rawMaxEmptyProcesses = computeEmptyProcessLimit(MAX_CACHED_PROCESSES);
    CUR_TRIM_EMPTY_PROCESSES = computeTrimEmptyApps(rawMaxEmptyProcesses);
    CUR_TRIM_CACHED_PROCESSES =
            computeTrimCachedApps(rawMaxEmptyProcesses, MAX_CACHED_PROCESSES);
}

// 下面的if判断,不管true还是false,默认情况下返回值都是totalProcessLimit的一半
// 因为EMPTY_APP_PERCENT默认设置为50
public static int computeEmptyProcessLimit(int totalProcessLimit) {
    if(USE_TRIM_SETTINGS && allowTrim()) {
        return totalProcessLimit*EMPTY_APP_PERCENT/100;
    } else {
        return totalProcessLimit/2;
    }
}

  上面的代码已经解析得很清楚了。如果内存比较紧张的话,其实可以将MAX_CACHED_PROCESSES设置低一些,这样系统中的空进程和缓存进程数量就会降低从而释放部分内存,不过这样也会带来副作用,就是跟默认情况相比,缓存下来的进程减少了,可能会导致后台存留的进程数量减少,那么用户在使用过程中命中缓存进程的几率就降低,影响用户体验。不过再进一步想想,系统内存都已经不住了,lmkd也不会让系统驻留这么多空进程和缓存进程的。具体大家可以自己试验。

回到updateOomAdjLocked继续分析

// 设置目前填充缓存进程的adj数值
int curCachedAdj = ProcessList.CACHED_APP_MIN_ADJ;
// 下一缓存进程使用的adj值,步进1
int nextCachedAdj = curCachedAdj+1;
int curEmptyAdj = ProcessList.CACHED_APP_MIN_ADJ;
int nextEmptyAdj = curEmptyAdj+2;
ProcessRecord selectedAppRecord = null;
long serviceLastActivity = 0;
int numBServices = 0;

// 遍历lru排序的所有进程
for (int i=N-1; i>=0; i--) {
    ProcessRecord app = mLruProcesses.get(i);
    // B service处理
    if (mEnableBServicePropagation && app.serviceb
            && (app.curAdj == ProcessList.SERVICE_B_ADJ)) {
        // 记录B service数量
        numBServices++;
        // 遍历当前进程app中的service
        for (int s = app.services.size() - 1; s >= 0; s--) {
            ServiceRecord sr = app.services.valueAt(s);
            if (DEBUG_OOM_ADJ) Slog.d(TAG,"app.processName = " + app.processName
                    + " serviceb = " + app.serviceb + " s = " + s + " sr.lastActivity = "
                    + sr.lastActivity + " packageName = " + sr.packageName
                    + " processName = " + sr.processName);
            // 如果该service距离上一次活动时间少于5秒则不进行处理
            if (SystemClock.uptimeMillis() - sr.lastActivity
                    < mMinBServiceAgingTime) {
                if (DEBUG_OOM_ADJ) {
                    Slog.d(TAG,"Not aged enough!!!");
                }
                continue;
            }
            // 记录距离上一次活动时间最短的应用和该service的时间
            // 即最近活动过得B service所在的进程
            if (serviceLastActivity == 0) {
                serviceLastActivity = sr.lastActivity;
                selectedAppRecord = app;
            } else if (sr.lastActivity < serviceLastActivity) {
                serviceLastActivity = sr.lastActivity;
                selectedAppRecord = app;
            }
        }
    }
.......

  上面这部分没有什么特殊的处理,从这里开始,我们就需要遍历所有的应用,并对应用进行处理了。上面的代码只是简单对B service进行处理,并将距离上一次活动到现在时间最短的那个应用到selectedAppRecord中,这里既然记录下来了,那么后面肯定是要用到的,这里留个记号。

// 调试需要,不管
if (DEBUG_OOM_ADJ && selectedAppRecord != null) Slog.d(TAG,
        "Identified app.processName = " + selectedAppRecord.processName
        + " app.pid = " + selectedAppRecord.pid);

if (!app.killedByAm && app.thread != null) {
    app.procStateChanged = false;
    // 调用computeOomAdjLocked计算除空进程和缓存进程外的应用的adj值
    computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, TOP_APP, true, now);

    // 如果进程的adj值没有设置的话
    if (app.curAdj >= ProcessList.UNKNOWN_ADJ) {
        switch (app.curProcState) {
            // 包含Activity的缓存进程
            case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
            case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
                // 设置当前进程的adj值
                app.curRawAdj = curCachedAdj;
                app.curAdj = app.modifyRawOomAdj(curCachedAdj);
                if (DEBUG_LRU && false) Slog.d(TAG_LRU, "Assigning activity LRU #" + i
                        + " adj: " + app.curAdj + " (curCachedAdj=" + curCachedAdj
                        + ")");
                if (curCachedAdj != nextCachedAdj) {
                    // 统计当前adj值所包含的缓存进程数量
                    stepCached++;
                    // 如果当前adj值中包含的缓存进程数量已经大于或者等于上面计算的每个slot包含的缓存进程数量
                    if (stepCached >= cachedFactor) {
                        // 重置当前adj值缓存进程数量
                        stepCached = 0;
                        // 重置curCachedAdj为nextCachedAdj
                        curCachedAdj = nextCachedAdj;
                        // nextCachedAdj步进加2
                        nextCachedAdj += 2;
                        if (nextCachedAdj > ProcessList.CACHED_APP_MAX_ADJ) {
                            nextCachedAdj = ProcessList.CACHED_APP_MAX_ADJ;
                        }
                    }
                }
                break;
            default:
                // 空进程处理代码,和缓存进程处理过程类似,这里不多做说明
                app.curRawAdj = curEmptyAdj;
                app.curAdj = app.modifyRawOomAdj(curEmptyAdj);
                if (DEBUG_LRU && false) Slog.d(TAG_LRU, "Assigning empty LRU #" + i
                        + " adj: " + app.curAdj + " (curEmptyAdj=" + curEmptyAdj
                        + ")");
                if (curEmptyAdj != nextEmptyAdj) {
                    stepEmpty++;
                    if (stepEmpty >= emptyFactor) {
                        stepEmpty = 0;
                        curEmptyAdj = nextEmptyAdj;
                        nextEmptyAdj += 2;
                        if (nextEmptyAdj > ProcessList.CACHED_APP_MAX_ADJ) {
                            nextEmptyAdj = ProcessList.CACHED_APP_MAX_ADJ;
                        }
                    }
                }
                break;
        }
    }

  这里的代码用到之前计算出来的cachedFactor和emptyFactor。这里举个例子说明一下,假设当前缓存进程为最大的16个,按照上面的计算有3个slot,那么每个slot就有5个进程,所以cacheFactor就等于5了。但是又按照上面写的代码,可以看到在adj为900的情况下,会存放5个空进程和5个缓存进程的,之后就是901用于存5个放缓存进程,而902用于存放5个空进程。之后,存放这两种进程的adj值步进都为2。这段代码执行效果大概如此,接下来我们接着分析。

// 提交oom值
applyOomAdjLocked(app, true, now, nowElapsed);

// 统计所有应用中各种状态的数量
switch (app.curProcState) {
    // 统计带Activity的缓存进程
    case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
    case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
        mNumCachedHiddenProcs++;
        numCached++;
        // 如果缓存进程数量超过系统允许的缓存进程上限
        if (numCached > cachedProcessLimit) {
            // 调用kill方法将进程杀死
            app.kill("cached #" + numCached, true);
        }
        break;
    case ActivityManager.PROCESS_STATE_CACHED_EMPTY:
        // 当空进程数量上过CUR_TRIM_EMPTY_PROCESSES,而且该空进程上次活动时间超过规定值就直接杀死
        if (numEmpty > mConstants.CUR_TRIM_EMPTY_PROCESSES
                && app.lastActivityTime < oldTime) {
            app.kill("empty for "
                    + ((oldTime + ProcessList.MAX_EMPTY_TIME - app.lastActivityTime)
                    / 1000) + "s", true);
        } else {
            numEmpty++;
            // 如果空进程超过emptyProcessLimit上限,杀死进程
            if (numEmpty > emptyProcessLimit) {
                app.kill("empty #" + numEmpty, true);
            }
        }
        break;
    default:
        mNumNonCachedProcs++;
        break;
}

  这上面就存在杀死进程的操作了。我们知道lmkd是在系统剩余内存达到某个临界点的时候才开始清除进程的。而这里则是空进程或者缓存进程数量超过系统规定值就开始清除一部分进程了。所以这两种清除进程的情况并不相同。

// 如果进程的isolated设置为true,而且进程的service数量少于等于0了,就清除该进程
if (app.isolated && app.services.size() <= 0) {
    app.kill("isolated not needed", true);
} else {
    // Keeping this process, update its uid.
    final UidRecord uidRec = app.uidRecord;
    if (uidRec != null) {
        uidRec.ephemeral = app.info.isInstantApp();
        if (uidRec.curProcState > app.curProcState) {
            uidRec.curProcState = app.curProcState;
        }
        if (app.foregroundServices) {
            uidRec.foregroundServices = true;
        }
    }
}
// 统计adj值大于等于桌面进程的进程数量
if (app.curProcState >= ActivityManager.PROCESS_STATE_HOME
        && !app.killedByAm) {
    numTrimming++;
}

  上面内容简单,只是对设置了isolated熟悉的进程进行判断清除,以及统计adj值大于HOME的进程的数量。

// 到这里就已经跳出了最开始的对所有进程进行遍历的那个for循环了

// 这里的selectedAppRecord是在开始的时候在统计B service时进行赋值的
// selectedAppRecord记录的是该进程距离上次活动的时间最短的那个B service
if ((numBServices > mBServiceAppThreshold) && (true == mAllowLowerMemLevel)
        && (selectedAppRecord != null)) {
    ProcessList.setOomAdj(selectedAppRecord.pid, selectedAppRecord.info.uid,
            ProcessList.CACHED_APP_MAX_ADJ);
    selectedAppRecord.setAdj = selectedAppRecord.curAdj;
    if (DEBUG_OOM_ADJ) Slog.d(TAG,"app.processName = " + selectedAppRecord.processName
                + " app.pid = " + selectedAppRecord.pid + " is moved to higher adj");
}

incrementProcStateSeqAndNotifyAppsLocked();

mNumServiceProcs = mNewNumServiceProcs;

// 统计最后的空进程和缓存进程数量总和
final int numCachedAndEmpty = numCached + numEmpty;
int memFactor;
// 判断系统内存因子
if (numCached <= mConstants.CUR_TRIM_CACHED_PROCESSES
        && numEmpty <= mConstants.CUR_TRIM_EMPTY_PROCESSES) {
    if (numCachedAndEmpty <= ProcessList.TRIM_CRITICAL_THRESHOLD) {
        memFactor = ProcessStats.ADJ_MEM_FACTOR_CRITICAL;
    } else if (numCachedAndEmpty <= ProcessList.TRIM_LOW_THRESHOLD) {
        memFactor = ProcessStats.ADJ_MEM_FACTOR_LOW;
    } else {
        memFactor = ProcessStats.ADJ_MEM_FACTOR_MODERATE;
    }
} else {
    memFactor = ProcessStats.ADJ_MEM_FACTOR_NORMAL;
}

if (DEBUG_OOM_ADJ) Slog.d(TAG_OOM_ADJ, "oom: memFactor=" + memFactor
        + " last=" + mLastMemoryLevel + " allowLow=" + mAllowLowerMemLevel
        + " numProcs=" + mLruProcesses.size() + " last=" + mLastNumProcesses);
if (memFactor > mLastMemoryLevel) {
    if (!mAllowLowerMemLevel || mLruProcesses.size() >= mLastNumProcesses) {
        memFactor = mLastMemoryLevel;
        if (DEBUG_OOM_ADJ) Slog.d(TAG_OOM_ADJ, "Keeping last mem factor!");
    }
}

  上面首先是对B service进行一番处理,不过暂时也看不出有什么影响。然后就根据numCached缓存进程的数量和numEmpty空进程的数量来判断当前系统内存紧张程度。这两类进程的数量越少,表示当前系统内存越紧张,内存等级就越高,内存等级由低到高分别为:ADJ_MEM_FACTOR_NORMAL、ADJ_MEM_FACTOR_MODERATE、ADJ_MEM_FACTOR_LOW和ADJ_MEM_FACTOR_CRITICAL,共四个等级。

  至于为什么缓存进程和空进程的数量越少会代表系统内存越紧张呢,这里解释一下。在讲解lowmemorykiller的时候有讲述到,如果系统内存达到阈值的话,会首先清除adj值最大的进程,而缓存进程和空进程的adj值属于最容易被清除的那一类。其次从上面可以看出,ActivityManagerService是尽可能保留空进程和缓存进程的,只有在这两类进程的数量超过系统规定的数量才会清除,所以进程变少了只能是lmkd来清除的。既然lmkd都动手清除进程了,那么就很好理解,缓存进程和空进程数量越少的话,那么系统内存当然就越紧张了。

mLastMemoryLevel = memFactor;
mLastNumProcesses = mLruProcesses.size();
boolean allChanged = mProcessStats.setMemFactorLocked(memFactor, !isSleepingLocked(), now);
final int trackerMemFactor = mProcessStats.getMemFactorLocked();
// 如果内存因子不是NORMAL级别的话,就进行处理
if (memFactor != ProcessStats.ADJ_MEM_FACTOR_NORMAL) {
    if (mLowRamStartTime == 0) {
        mLowRamStartTime = now;
    }
    int step = 0;
    int fgTrimLevel;
    switch (memFactor) {
        case ProcessStats.ADJ_MEM_FACTOR_CRITICAL:
            fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL;
            break;
        case ProcessStats.ADJ_MEM_FACTOR_LOW:
            fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW;
            break;
        default:
            fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE;
            break;
    }
    int factor = numTrimming/3;
    int minFactor = 2;
    if (mHomeProcess != null) minFactor++;
    if (mPreviousProcess != null) minFactor++;
    if (factor < minFactor) factor = minFactor;
    // 设置当前trim等级为最高,即要求应用进最大可能释放内存
    int curLevel = ComponentCallbacks2.TRIM_MEMORY_COMPLETE;

  这里判断如果内存因子级别不是NORMAL的话,就需要对所有的进行进行内存回收操作。switch中根据内存因子的级别设置fgTrimLevel为对应的级别。这里,也和之前对缓存进程和空进程的处理类似,进行分组,factor为每组进程的数量。

// 再次开始遍历所有进程
for (int i=N-1; i>=0; i--) {
    ProcessRecord app = mLruProcesses.get(i);
    if (allChanged || app.procStateChanged) {
        setProcessTrackerStateLocked(app, trackerMemFactor, now);
        app.procStateChanged = false;
    }
    // 进程的state大于HOME进程的state
    if (app.curProcState >= ActivityManager.PROCESS_STATE_HOME
            && !app.killedByAm) {
        if (app.trimMemoryLevel < curLevel && app.thread != null) {
            try {
                if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
                        "Trimming memory of " + app.processName + " to " + curLevel);
                // 调用app的接口,让其自动释放内存
                app.thread.scheduleTrimMemory(curLevel);
            } catch (RemoteException e) {
            }
            if (false) {
                if (curLevel >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE
                        && app != mHomeProcess && app != mPreviousProcess) {
                    mStackSupervisor.scheduleDestroyAllActivities(app, "trim");
                }
            }
        }
        // 设置进程当前trim等级
        app.trimMemoryLevel = curLevel;
        step++;
        // 降低后续进程的trim等级
        if (step >= factor) {
            step = 0;
            switch (curLevel) {
                case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
                    curLevel = ComponentCallbacks2.TRIM_MEMORY_MODERATE;
                    break;
                case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
                    curLevel = ComponentCallbacks2.TRIM_MEMORY_BACKGROUND;
                    break;
            }
        }

  mLruProcesses中的进程是按照Lru算法排列的,Lru是最近最少使用的意思。那么就是所mLruProcesses中第一个应用时最近最少使用到的。在系统内存紧张的情况下,当然要最近很少使用到的,被缓存起来的应用尽可能释放内存的。这里进行内存释放走的确实另一条道路了,这里会调用app.thread.scheduleTrimMemory要求应用进行内存释放。这个调用最后会调用到应用Activity的OnTrimMemory接口,这样开发者就可以在自己的应用中选择哪些内存是可以进行释放的,如果开发者没有实现这个接口进行内存释放,那么lmkd在内存较低的时候,很可能就会将你开发的应用杀死了。

  大于HOME级别的应用包括上一次使用的应用、缓存进程以及空进程。在释放之前,就已经将应用分组了的,如果应用数量较多,在不近step超过factor因子时,我们会将后续的Trim级别降低。

// 对重要程度为PROCESS_STATE_HEAVY_WEIGHT的进程进行处理
} else if (app.curProcState == ActivityManager.PROCESS_STATE_HEAVY_WEIGHT) {
    // 只对当前进程的trim级别比TRIM_MEMORY_BACKGROUND小的进程进行处理
    if (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_BACKGROUND
            && app.thread != null) {
        try {
            if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
                    "Trimming memory of heavy-weight " + app.processName
                    + " to " + ComponentCallbacks2.TRIM_MEMORY_BACKGROUND);
            app.thread.scheduleTrimMemory(
                    ComponentCallbacks2.TRIM_MEMORY_BACKGROUND);
        } catch (RemoteException e) {
        }
    }
    app.trimMemoryLevel = ComponentCallbacks2.TRIM_MEMORY_BACKGROUND;
} else {
    // 剩余情况处理
    // 进程的State处于PROCESS_STATE_IMPORTANT_BACKGROUND和PROCESS_STATE_HEAVY_WEIGHT之间
    if ((app.curProcState >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
            || app.systemNoUi) && app.pendingUiClean) {
        final int level = ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN;
        if (app.trimMemoryLevel < level && app.thread != null) {
            try {
                if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
                        "Trimming memory of bg-ui " + app.processName
                        + " to " + level);
                app.thread.scheduleTrimMemory(level);
            } catch (RemoteException e) {
            }
        }
        app.pendingUiClean = false;
    }
    // 最后对最重要的应用做最后的内存回收
    if (app.trimMemoryLevel < fgTrimLevel && app.thread != null) {
        try {
            if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
                    "Trimming memory of fg " + app.processName
                    + " to " + fgTrimLevel);
            app.thread.scheduleTrimMemory(fgTrimLevel);
        } catch (RemoteException e) {
        }
    }
    app.trimMemoryLevel = fgTrimLevel;
}

  冲上面往下看,应用的重要程度越来越高,重要程度不同的应用,所使用的Trim级别也不近相同。越不重要的应用,越应该尽可能多的释放内存,以确保系统内存主意维持其余重要进程或者新进程使用。上面这些都是当内存级别不是NORMAL情况下的处理,下面看看当内存紧张程度为NORMAL时,系统是如何处理的。

if (memFactor != ProcessStats.ADJ_MEM_FACTOR_NORMAL) {
// 这部分已经在上面分析了
..................
} else {
    if (mLowRamStartTime != 0) {
        mLowRamTimeSinceLastIdle += now - mLowRamStartTime;
        mLowRamStartTime = 0;
    }
    for (int i=N-1; i>=0; i--) {
        ProcessRecord app = mLruProcesses.get(i);
        if (allChanged || app.procStateChanged) {
            setProcessTrackerStateLocked(app, trackerMemFactor, now);
            app.procStateChanged = false;
        }
        if ((app.curProcState >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
                || app.systemNoUi) && app.pendingUiClean) {
            if (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN
                    && app.thread != null) {
                try {
                    if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
                            "Trimming memory of ui hidden " + app.processName
                            + " to " + ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
                    app.thread.scheduleTrimMemory(
                            ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
                } catch (RemoteException e) {
                }
            }
            app.pendingUiClean = false;
        }
        app.trimMemoryLevel = 0;
    }
}

  如果系统内存充足的话,就只对PROCESS_STATE_IMPORTANT_BACKGROUND以上级别的应用以TRIM_MEMORY_UI_HIDDEN级别进行内存回收。到这里,基本上对应用的处理就完成了,这个方法后面还有一部分代码,但是看那部分代码是对UID进程处理的,貌似和现在分析的主题不是特别搭,而且暂时也没看懂做了什么特殊处理。所以剩余的代码,这里就不多做分析了。

总结

  updateOomAdjLocked方法完成下面三个操作

  1. 更新所有应用等oom_adj值,其中非cachedProcess和emptyProcess进程等oom_adj值的计算通过调用computeOomAdjLocked方法完成,而cachedProcess和emptyProcess进程则按照由近至远的方式交替从小至大的分配oom_adj值
  2. 根据cachedPrcess和emptyProcess的数量判断是否超过数量上限,超过则杀死进程,越久远的进程在超过时优先被杀死。
  3. 根据cachedPrcess和emptyProcess的数量判断当前内存的紧张程度生成对应等级,根据当前系统内存等级,来要求进程做对应的进程内的回收。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d 博主赞过: