frameworks/base/services/core/java/com/android/server/am/OomAdjuster.java,入口是assignCachedAdjIfNecessary
,updateAndTrimProcessLSP
方法
@GuardedBy({"mService", "mProcLock"})
private void assignCachedAdjIfNecessary(ArrayList<ProcessRecord> lruList) {
final int numLru = lruList.size();
// cacheAdj值默认起点是900
int curCachedAdj = ProcessList.CACHED_APP_MIN_ADJ;
// 那么下一个cache进程,则在当前进程的adj基础上 + (10),例如:900 + (5 * 2) = 910
// 所以cache进程的标志为:910,920,930,940等
int nextCachedAdj = curCachedAdj + (ProcessList.CACHED_APP_IMPORTANCE_LEVELS * 2);
int curCachedImpAdj = 0;
// emptyADj值起点为:900 + 5 = 905
int curEmptyAdj = ProcessList.CACHED_APP_MIN_ADJ + ProcessList.CACHED_APP_IMPORTANCE_LEVELS;
// 那么下一个empty进程,则在当前进程的adj基础上 + (10),例如:905 + (5 * 2) = 915
// 所以分辨empty可以通过:905,915,925,935,945来分辨
int nextEmptyAdj = curEmptyAdj + (ProcessList.CACHED_APP_IMPORTANCE_LEVELS * 2);
// empty进程存在的上限:cache进程的上限CUR_MAX_CACHED_PROCESSES(32)/2 = 16个
final int emptyProcessLimit = mConstants.CUR_MAX_EMPTY_PROCESSES;
// cache进程存在的上限:CUR_MAX_CACHED_PROCESSES(32)个 - emptyProcessLimit(16) = 16个
final int cachedProcessLimit = mConstants.CUR_MAX_CACHED_PROCESSES
- emptyProcessLimit;
// 所以cache进程数量上限是32个 - emptyProcessLimit的数量
// emptyProcessLimit又是cache数量的一半
// empty进程数量 = empty总数量 - 非cache - cache隐藏
int numEmptyProcs = numLru - mNumNonCachedProcs - mNumCachedHiddenProcs;
...
int cachedFactor = (mNumCachedHiddenProcs > 0 ? (mNumCachedHiddenProcs + mNumSlots - 1) : 1)
/ mNumSlots;
int emptyFactor = (numEmptyProcs + mNumSlots - 1) / mNumSlots;
// 遍历所有empty和cache进程
for (int i = numLru - 1; i >= 0; i--) {
ProcessRecord app = lruList.get(i);
final ProcessStateRecord state = app.mState;
// 如果进程adj值确实是 >=UNKNOWN_ADJ,说明是empty或cache
if (!app.isKilledByAm() && app.getThread() != null && state.getCurAdj()
>= ProcessList.UNKNOWN_ADJ) {
final ProcessServiceRecord psr = app.mServices;
switch (state.getCurProcState()) {
// 如果是cache进程,计算curCachedImpAdj的数量
case PROCESS_STATE_CACHED_ACTIVITY:
case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
case ActivityManager.PROCESS_STATE_CACHED_RECENT:
// Figure out the next cached level, taking into account groups.
...
// 根据cache因子计算下一个cache进程的adj值
if (!inGroup && curCachedAdj != nextCachedAdj) {
stepCached++;
curCachedImpAdj = 0;
if (stepCached >= cachedFactor) {
stepCached = 0;
curCachedAdj = nextCachedAdj;
**nextCachedAdj += ProcessList.CACHED_APP_IMPORTANCE_LEVELS * 2;**
// 最大不能超过999
if (nextCachedAdj > ProcessList.CACHED_APP_MAX_ADJ) {
nextCachedAdj = ProcessList.CACHED_APP_MAX_ADJ;
}
}
}
// 设置cache adj值
state.setCurRawAdj(curCachedAdj + curCachedImpAdj);
state.setCurAdj(psr.modifyRawOomAdj(curCachedAdj + curCachedImpAdj));
break;
default:
// Figure out the next cached level.
// 计算empty值
if (curEmptyAdj != nextEmptyAdj) {
stepEmpty++;
if (stepEmpty >= emptyFactor) {
stepEmpty = 0;
curEmptyAdj = nextEmptyAdj;
// 计算下一次empty值
nextEmptyAdj += ProcessList.CACHED_APP_IMPORTANCE_LEVELS * 2;
if (nextEmptyAdj > ProcessList.CACHED_APP_MAX_ADJ) {
nextEmptyAdj = ProcessList.CACHED_APP_MAX_ADJ;
}
}
}
state.setCurRawAdj(curEmptyAdj);
state.setCurAdj(psr.modifyRawOomAdj(curEmptyAdj));
break;
}
}
}
}
所以以上方法的主要作用就是处理empty和cache进程的adj值
然后约束其不能超过999最大值,然后继续设置下一次Empty/Cache的Adj值间隔+=10(因为这是遍历所有cache/Empty进程),然后设置adj值即可,所以总结一下:设置empty和cache进程adj值起点,防止每个进程间隔太近导致同时被kill,造成卡顿等情况,循环遍历每个进程,每个进程必须间隔10,且用步进为5来区分是cache还是empty,并约束不能超过999的最大adj值,然后调用setCurRawAdj和setCurAdj设置最终值即可
继续看updateAndTrimProcessLSP
方法,该方法用于kill这些进程
@GuardedBy({"mService", "mProcLock"})
private boolean updateAndTrimProcessLSP(final long now, final long nowElapsed,
final long oldTime, final ActiveUids activeUids) {
// 获取所有进程
ArrayList<ProcessRecord> lruList = mProcessList.getLruProcessesLOSP();
final int numLru = lruList.size();
// 获取empty和cache进程数量上限,已经讲过了
// emptyProcessLimit:32 / 2 = 16
// cachedProcessLimit:32 - emptyProcessLimit = 16
final int emptyProcessLimit = mConstants.CUR_MAX_EMPTY_PROCESSES;
final int cachedProcessLimit = mConstants.CUR_MAX_CACHED_PROCESSES
- emptyProcessLimit;
int lastCachedGroup = 0;
int lastCachedGroupUid = 0;
int numCached = 0;
int numCachedExtraGroup = 0;
int numEmpty = 0;
int numTrimming = 0;
// 遍历所有进程
for (int i = numLru - 1; i >= 0; i--) {
ProcessRecord app = lruList.get(i);
final ProcessStateRecord state = app.mState;
// 要求进程存在,即ActivityThread存在
if (!app.isKilledByAm() && app.getThread() != null) {
// We don't need to apply the update for the process which didn't get computed
if (state.getCompletedAdjSeq() == mAdjSeq) {
applyOomAdjLSP(app, true, now, nowElapsed);
}
// 获取该进程的所有服务
final ProcessServiceRecord psr = app.mServices;
// Count the number of process types.
switch (state.getCurProcState()) {
// 如果进程状态是cached
case PROCESS_STATE_CACHED_ACTIVITY:
case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
mNumCachedHiddenProcs++;
// cached进程数量++
numCached++;
final int connectionGroup = psr.getConnectionGroup();
if (connectionGroup != 0) {
if (lastCachedGroupUid == app.info.uid
&& lastCachedGroup == connectionGroup) {
// If this process is the next in the same group, we don't
// want it to count against our limit of the number of cached
// processes, so bump up the group count to account for it.
// 如果这个进程是和上个进程属于同一个组内,我们不希望它计入我们缓存进程数量的限制
numCachedExtraGroup++;
} else {
lastCachedGroupUid = app.info.uid;
lastCachedGroup = connectionGroup;
}
} else {
lastCachedGroupUid = lastCachedGroup = 0;
}
// 如果cached进程数量 > 16个则进行主动kill
// ,要排除numCachedExtraGroup(因为目前的进程和上一个进程属于同一个组))
if ((numCached - numCachedExtraGroup) > cachedProcessLimit) {
app.killLocked("cached #" + numCached,
ApplicationExitInfo.REASON_OTHER,
ApplicationExitInfo.SUBREASON_TOO_MANY_CACHED,
true);
}
break;
case PROCESS_STATE_CACHED_EMPTY:
// 如果是empty进程
// 如果empty进程数量 > (MAX_CACHED_PROCESSES(32) / 2) / 2 = 8并且该进程最近活跃时间在30以内,则进行主动kill
// 一般empty只允许存活30分钟,但如果超过了8个也主动kill,所以empty进程超过30分钟,但在8个以内则不会被杀
if (numEmpty > mConstants.CUR_TRIM_EMPTY_PROCESSES
&& app.getLastActivityTime() < oldTime) {
app.killLocked("empty for " + ((oldTime + ProcessList.MAX_EMPTY_TIME
- app.getLastActivityTime()) / 1000) + "s",
ApplicationExitInfo.REASON_OTHER,
ApplicationExitInfo.SUBREASON_TRIM_EMPTY,
true);
} else {// 会先执行else来计算empty进程数量
numEmpty++;
// 如果进程数量超过16个,不解释,直接kill
if (numEmpty > emptyProcessLimit) {
app.killLocked("empty #" + numEmpty,
ApplicationExitInfo.REASON_OTHER,
ApplicationExitInfo.SUBREASON_TOO_MANY_EMPTY,
true);
}
}
break;
default:
mNumNonCachedProcs++;
break;
}
// 如果是孤立进程且没有服务在运行,则也直接kill
if (app.isolated && psr.numberOfRunningServices() <= 0
&& app.getIsolatedEntryPoint() == null) {
// If this is an isolated process, there are no services
// running in it, and it's not a special process with a
// custom entry point, then the process is no longer
// needed. We agressively kill these because we can by
// definition not re-use the same process again, and it is
// good to avoid having whatever code was running in them
// left sitting around after no longer needed.
app.killLocked("isolated not needed", ApplicationExitInfo.REASON_OTHER,
ApplicationExitInfo.SUBREASON_ISOLATED_NOT_NEEDED, true);
} else {
// Keeping this process, update its uid.
updateAppUidRecLSP(app);
}
// 大于>home基本上都是cache或者empty进程
if (state.getCurProcState() >= ActivityManager.PROCESS_STATE_HOME
&& !app.isKilledByAm()) {
// 会记录这种进程的次数,此时还不做处理
numTrimming++;
}
}
}
mProcessList.incrementProcStateSeqAndNotifyAppsLOSP(activeUids);
// 传递cached进程数量,empty数量,numTrimming数量,决定内存处于哪个阶段等级
return mService.mAppProfiler.updateLowMemStateLSP(numCached, numEmpty, numTrimming);
}
所以以内逻辑可以分为:
updateLowMemStateLSP
调整内存等级frameworks/base/services/core/java/com/android/server/am/AppProfiler.java,主要分析updateLowMemStateLSP
@GuardedBy({"mService", "mProcLock"})
boolean updateLowMemStateLSP(int numCached/*cached数量*/, int numEmpty/*empty数量*/, int numTrimming/*进程>=PROCESS_STATE_HOME的数量*/) {
final long now = SystemClock.uptimeMillis();
// 内存因子
int memFactor;
// 如果kernel支持mLowMemDetector功能,才会有mLowMemDetector对象存在
// 如果mLowMemDetector存在,默认内存因子为ADJ_MEM_FACTOR_NORMAL(0)
if (mLowMemDetector != null && mLowMemDetector.isAvailable()) {
memFactor = mLowMemDetector.getMemFactor();
} else {// 讨论此类情况
// 如果cached进程数量 <= (MAX_CACHED_PROCESSES(32) - 16) / 3 = 5个(因为是int)
// 并且empty数量 <= 16 / 2 = 8个才会去调整内存因子,内存因子越大,内存压力越大
if (numCached <= mService.mConstants.CUR_TRIM_CACHED_PROCESSES
&& numEmpty <= mService.mConstants.CUR_TRIM_EMPTY_PROCESSES) {
// 计算empty+cached总进程数量
final int numCachedAndEmpty = numCached + numEmpty;
// 如果总数量 <= 3---微调临界阈值,则内存因子为3
if (numCachedAndEmpty <= ProcessList.TRIM_CRITICAL_THRESHOLD) {
memFactor = ADJ_MEM_FACTOR_CRITICAL;
// 如果总数量 <= 5,则赋予5,所以数量在3~5个,则内存因子为2
} else if (numCachedAndEmpty <= ProcessList.TRIM_LOW_THRESHOLD) {
memFactor = ADJ_MEM_FACTOR_LOW;
} else {// 其他情况,为1
memFactor = ADJ_MEM_FACTOR_MODERATE;
}
} else {// 如果进程数量大于了规定的5 + 8个,则赋予0
memFactor = ADJ_MEM_FACTOR_NORMAL;
}
}
...
// 记录当前的内存因子为最新调整的一次
mLastMemoryLevel = memFactor;
mLastNumProcesses = mService.mProcessList.getLruSizeLOSP();
boolean allChanged;
int trackerMemFactor;
synchronized (mService.mProcessStats.mLock) {
// 将内存因子保存到ProcessStats中或ServiceState中
allChanged = mService.mProcessStats.setMemFactorLocked(memFactor,
mService.mAtmInternal == null || !mService.mAtmInternal.isSleeping(), now);
// 获取上次的内存因子
trackerMemFactor = mService.mProcessStats.getMemFactorLocked();
}
// 如果内存因子不属于正常情况,进入低内存状态
if (memFactor != ADJ_MEM_FACTOR_NORMAL) {
if (mLowRamStartTime == 0) {
mLowRamStartTime = now;
}
// 内存水平
int fgTrimLevel;
// 通过内存因子,得到内存TrimLevel等级
switch (memFactor) {// 如果内存因子是3,则fgTrimLevel为15
case ADJ_MEM_FACTOR_CRITICAL:
// 您正在运行的进程应该释放尽可能多的非关键资源,以便将内存用于其他地方
fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL;
break;
case ADJ_MEM_FACTOR_LOW: // 如果内存因子为2,则fgTrimLevel为10
// 您正在运行的进程应该释放不需要的资源,以便将内存用于其他地方。
fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW;
break;
default:
// 您正在运行的进程可能希望释放一些不需要的资源,以便在其他地方使用,fgTrimLevel为5
fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE;
break;
}
...
// 最大内存等级,80
final int[] curLevel = {ComponentCallbacks2.TRIM_MEMORY_COMPLETE};
// 遍历所有进程
mService.mProcessList.forEachLruProcessesLOSP(true, app -> {
final ProcessProfileRecord profile = app.mProfile;
// 获取该进程的内存水平
final int trimMemoryLevel = profile.getTrimMemoryLevel();
final ProcessStateRecord state = app.mState;
// 获取进程状态
final int curProcState = state.getCurProcState();
IApplicationThread thread;
// 如果进程状态>=home,代表进程状态不是很好
if (curProcState >= ActivityManager.PROCESS_STATE_HOME && !app.isKilledByAm()) {
...
// 默认设置最大内存水平
thread.scheduleTrimMemory(curLevel[0])
} else if (curProcState == ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
&& !app.isKilledByAm()) {
...
thread.scheduleTrimMemory(ComponentCallbacks2.TRIM_MEMORY_BACKGROUND);
profile.setTrimMemoryLevel(ComponentCallbacks2.TRIM_MEMORY_BACKGROUND);
} else {
if ((curProcState >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
|| state.isSystemNoUi()) && profile.hasPendingUiClean()) {
thread.scheduleTrimMemory(level);
}
if (trimMemoryLevel < fgTrimLevel && (thread = app.getThread()) != null) {
try {
if (DEBUG_SWITCH || DEBUG_OOM_ADJ) {
Slog.v(TAG_OOM_ADJ, "Trimming memory of fg " + app.processName
+ " to " + fgTrimLevel);
}
thread.scheduleTrimMemory(fgTrimLevel);
} catch (RemoteException e) {
}
}
profile.setTrimMemoryLevel(fgTrimLevel);
}
});
} else {// 内存水平正常的情况,代表内存不紧张的情况
mService.mProcessList.forEachLruProcessesLOSP(true, app -> {
final ProcessProfileRecord profile = app.mProfile;
final IApplicationThread thread;
final ProcessStateRecord state = app.mState;
if (allChanged || state.hasProcStateChanged()) {
mService.setProcessTrackerStateLOSP(app, trackerMemFactor, now);
state.setProcStateChanged(false);
}
if ((state.getCurProcState() >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
|| state.isSystemNoUi()) && profile.hasPendingUiClean()) {
thread.scheduleTrimMemory(ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
}
profile.setTrimMemoryLevel(0);
});
}
return allChanged;
}
以上就是根据cached进程数量和empty进程数量来确定内存因子,再由内存因子决定内存水平(fgTrimLevel),然后再根据进程状态调用setTrimMemoryLevel
和scheduleTrimMemory
设置不同的内存水平。
当前的cachedProcess和emptyProcess进程的数量来综合判定当前进程的等内存级,这两类进程的数量越少, 表示系统内存越紧张,内存等级越高。
lowmemeorykiller的机制又会在系统可用内存不足时杀死这些进程, 所以在后台进程和空进程数量少于一定数量时,便表示了系统以及触发了lowmemrorykiller的机制,即表示当前系统内存的紧张程度
总结:后台进程与空进程越多表示内存越富裕,越少表示内存越紧张,这些内存level会传递给app,如果activity重写了OnTrimMemory
,则会将当前level传递给activity,开发者可以根据level情况来释放资源,然后内存level也会传递给WindowManagerGlobal#trimMemory
,如果内存level≥60,则销毁与已知窗口关联的所有surface和layer,以及资源也会被销毁,但进程可能仍然存在,不过再次进入该进程,需要重新加载资源了
内存因子参数
内存因子对应的内存level介绍
ADJ_MEM_FACTOR_CRITICAL
,会设置这个水平ADJ_MEM_FACTOR_LOW
*,会设置这个水平ADJ_MEM_FACTOR_CRITICAL
和ADJ_MEM_FACTOR_LOW
,默认内存因子对应的水平都是这个