Android oom_adj 更新原理(一)

2024-02-11 16:59
文章标签 android 更新 原理 adj oom

本文主要是介绍Android oom_adj 更新原理(一),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

源码基于:Android R

0. 前言

通过之前的两篇博文《lmkd 机制详解》《oom_adj 内存水位算法剖析》中,根据计算出来的 min_score_adj 选择大于该值的 oom_adj 的进程进行 kill 处理。 oom_adj 随着应用状态的不同其值也是伴随着变化的。

本文将通过源码剖析 oom_adj 更新的原理。

1. adj 概念

Android 系统的设计理念希望应用进程尽可能的长时间的存活,以此来提升用户体验。在Android 中,应用首次打开会比较慢,这个过程包含进程的创建、application 初始化、应用其他逻辑等,所以,在应用退出时并非直接exit 进程或被 kill,而是会存活一段时间,这样就保证在下次启动时跟快启动。

当然,物极必反。在大量应用启动后就会造成内存大量使用,手机性能会随着下降。如果放任所有进程存活,系统内存就会枯竭。因此需要合理的回收机制,Android 中通过 adj 和 process state 两个重要的标准来进行衡量。系统根据进程组建的状态来决定每个进程的优先级adj 值,然后再根据一定的策略选择优先级低的进程kill,以此类推,通过回收预期的系统资源来保证系统的正常运转。

2. adj 等级

frameworks/base/services/core/java/com/android/server/am/ProcessList.java

ADJ 等级取值说明
UNKNOWN_ADJ1001用于特定地方,一般指将要cache进程,不知道确切值
CACHED_APP_MAX_ADJ999不可见进程的最大值,进程可以无任何干扰的被杀
CACHED_APP_LMK_FIRST_ADJ950oom_adj 等级第一个允许被杀的level,不能等于CACHED_APP_MAX_ADJ
CACHED_APP_MIN_ADJ900不可见进程的最小值
SERVICE_B_ADJ800B List中的Service(较老的、使用可能性更小)
PREVIOUS_APP_ADJ700上一个App的进程(往往通过按返回键)
HOME_APP_ADJ600Home进程
SERVICE_ADJ500app service 进程,杀掉它一般不会有太大的影响
HEAVY_WEIGHT_APP_ADJ400后台的重量级进程,system/rootdir/init.rc文件中startup
BACKUP_APP_ADJ300备份进程,杀掉它不完全致命,但不好
PERCEPTIBLE_LOW_APP_ADJ250被用户或系统绑定的进程,比service 要重要,但是如果被杀掉,不会立即影响客户的感官
PERCEPTIBLE_APP_ADJ200可感知的进程,如后台music 播放
VISIBLE_APP_ADJ100可视进程
PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ50recently TOP 进程
FOREGROUND_APP_ADJ0前台进程
PERSISTENT_SERVICE_ADJ-700关联系统的进程或一个常驻进程
PERSISTENT_PROC_ADJ-800

系统常驻进程,例如telephony

绝对不想杀,但不完全致命

SYSTEM_ADJ-900系统进程
NATIVE_ADJ-1000native 进程,不归系统管理,所以没有oom_adj 适配

3. 进程状态

状态等级取值说明
PROCESS_STATE_CACHED_EMPTY19进程将被cached,且是空进程
PROCESS_STATE_CACHED_RECENT18进程将被cached,而且有个activity与一个recent task 通信
PROCESS_STATE_CACHED_ACTIVITY_CLIENT17进程将被cached,而且是另外有activities 的cached进程的client端
PROCESS_STATE_CACHED_ACTIVITY16进程将被cached,且内涵activities
PROCESS_STATE_LAST_ACTIVITY15后台进程,且拥有上一次显示的Activity
PROCESS_STATE_HOME14后台进程,且拥有home Activity
PROCESS_STATE_HEAVY_WEIGHT13后台进程,但无法执行restore,因此尽量避免kill该进程
PROCESS_STATE_TOP_SLEEPING12与PROCESS_STATE_TOP一样,但此时设备正处于休眠状态
PROCESS_STATE_RECEIVER11后台进程,且正在运行receiver
PROCESS_STATE_SERVICE10后台进程,且正在运行service
PROCESS_STATE_BACKUP9后台进程,正在运行backup/restore操作
PROCESS_STATE_TRANSIENT_BACKGROUND8短暂的后台进程,需要keep running
PROCESS_STATE_IMPORTANT_BACKGROUND7对用户重要的进程,但并不能感知到
PROCESS_STATE_IMPORTANT_FOREGROUND6对用户重要的进程,且可以感知到
PROCESS_STATE_BOUND_FOREGROUND_SERVICE5进程拥有一个前台Service,且由系统绑定
PROCESS_STATE_FOREGROUND_SERVICE4进程拥有一个前台service
PROCESS_STATE_BOUND_TOP3被绑定为TOP app 的进程
PROCESS_STATE_TOP2进程拥有当前top activities,对于用户是可见的
PROCESS_STATE_PERSISTENT_UI1进程为persisent 系统进程,且doing UI
PROCESS_STATE_PERSISTENT0常驻的系统进程

4. 3个核心函数

oom_adj 涉及三个重要函数:

  • updateOomAdjLocked():更新adj,当目标进程为空,或者被杀则返回false;否则返回true;
  • computeOomAdjLocked():计算adj,返回计算后RawAdj值;
  • applyOomAdjLocked():应用adj,当需要杀掉目标进程则返回 false;否则返回true。

其中 computeOomAdjLocked()applyOomAdjLocked() 都是在 updateOomAdjLocked() 中调用到,代码位于 frameworks/base/services/core/java/com/android/server/am/OomAdjuster.java 中。

当四大组件状态改变时会通过 updateOomAdjLocked() 来同步更新相应进程的 ADJ 优先级。需要注意的是,当同一个进程有多个决定其优先级的组件状态时,取优先级最高的 ADJ 作为最终的 ADJ。另外,进程会通过设置 maxAdj 来限定ADJ 的上限。

5. updateOomAdjLocked() 简析

在上一节中我们得知 oom_adj 涉及三个重要的函数,源头都是 updateOomAdjLocked(),在详细剖析该函数之前先来了解下。

首先该接口的源头都位于 AMS 中,在AMS 中提供了三个接口:

frameworks/base/services/core/java/com/android/server/am/AMS.javafinal void updateOomAdjLocked(String oomAdjReason) {mOomAdjuster.updateOomAdjLocked(oomAdjReason);}final void updateOomAdjLocked(ProcessRecord app, String oomAdjReason) {mOomAdjuster.updateOomAdjLocked(app, oomAdjReason);}final boolean updateOomAdjLocked(ProcessRecord app, boolean oomAdjAll,String oomAdjReason) {return mOomAdjuster.updateOomAdjLocked(app, oomAdjAll, oomAdjReason);}

AMS 中提供的三个接口分别对应 OomAdjuster 中的三个接口,四大组件在更新 ADJ 时都是通过这里的接口。

6. ADJ 更新时机

6.1 activity 中更新 oom_adj

  • ASS.realStartActivityLocked():启动Activity
  • AS.resumeTopActivityInnerLocked():恢复栈顶Activity
  • AS.finishCurrentActivityLocked():结束当前Activity
  • AS.destroyActivityLocked():摧毁当前Activity

6.2 service 中更新 oom_adj

  • ActiveServices.realStartServiceLocked():启动服务
  • ActiveServices.bindServiceLocked():绑定服务(只更新当前app)
  • ActiveServices.unbindServiceLocked():解绑服务 (只更新当前app)
  • ActiveServices.bringDownServiceLocked():结束服务 (只更新当前app)
  • ActiveServices.sendServiceArgsLocked():在bringup或则cleanup服务过程调用 (只更新当前app)

6.3 broadcast 中更新 oom_adj

  • BQ.processNextBroadcast():处理下一个广播
  • BQ.processCurBroadcastLocked():处理当前广播
  • BQ.deliverToRegisteredReceiverLocked():分发已注册的广播 (只更新当前app)

6.4 ContentProvider 中更新 oom_adj

  • AMS.removeContentProvider():移除provider
  • AMS.publishContentProviders():发布provider (只更新当前app)
  • AMS.getContentProviderImpl():获取provider (只更新当前app)

6.5 Process相关

  • AMS.setSystemProcess():创建并设置系统进程
  • AMS.addAppLocked():创建persistent进程
  • AMS.attachApplicationLocked():进程创建后attach到system_server的过程;
  • AMS.trimApplications():清除没有使用app
  • AMS.appDiedLocked():进程死亡
  • AMS.killAllBackgroundProcesses():杀死所有后台进程.即(ADJ>9或removed=true的普通进程)
  • AMS.killPackageProcessesLocked():以包名的形式 杀掉相关进程

7. updateOomAdjLocked() 一参

AMS 中一个参数的更新最终会调用到 OomAdjuster.java 中:

frameworks/base/services/core/java/com/android/server/am/OomAdjuster.javavoid updateOomAdjLocked(String oomAdjReason) {// 前台的app(若无app 处于前台则是TASK栈栈顶的应用)final ProcessRecord topApp = mService.getTopAppLocked();// 一参方法最终调用这里updateOomAdjLockedInner(oomAdjReason, topApp , null, null, true, true);}

参数是 oomAdjReason,定义在 OomAdjuster.java 文件最开始的地方:

    static final String OOM_ADJ_REASON_METHOD = "updateOomAdj";static final String OOM_ADJ_REASON_NONE = OOM_ADJ_REASON_METHOD + "_meh";static final String OOM_ADJ_REASON_ACTIVITY = OOM_ADJ_REASON_METHOD + "_activityChange";static final String OOM_ADJ_REASON_FINISH_RECEIVER = OOM_ADJ_REASON_METHOD + "_finishReceiver";static final String OOM_ADJ_REASON_START_RECEIVER = OOM_ADJ_REASON_METHOD + "_startReceiver";static final String OOM_ADJ_REASON_BIND_SERVICE = OOM_ADJ_REASON_METHOD + "_bindService";static final String OOM_ADJ_REASON_UNBIND_SERVICE = OOM_ADJ_REASON_METHOD + "_unbindService";static final String OOM_ADJ_REASON_START_SERVICE = OOM_ADJ_REASON_METHOD + "_startService";static final String OOM_ADJ_REASON_GET_PROVIDER = OOM_ADJ_REASON_METHOD + "_getProvider";static final String OOM_ADJ_REASON_REMOVE_PROVIDER = OOM_ADJ_REASON_METHOD + "_removeProvider";static final String OOM_ADJ_REASON_UI_VISIBILITY = OOM_ADJ_REASON_METHOD + "_uiVisibility";static final String OOM_ADJ_REASON_WHITELIST = OOM_ADJ_REASON_METHOD + "_whitelistChange";static final String OOM_ADJ_REASON_PROCESS_BEGIN = OOM_ADJ_REASON_METHOD + "_processBegin";static final String OOM_ADJ_REASON_PROCESS_END = OOM_ADJ_REASON_METHOD + "_processEnd";

一参的 updateOomAdjLocked() 最终调用的是 updateOomAdjLockedInner(),就是更新 LRU list (所有由 AMS 启动的进程都会保存在这里)中所有的 process 的 oom adj,并且对 cached 进程和 empty进程进行处理,详细看下文第 11 节。

8. updateOomAdjLocked() 二参

在了解完 updateOomAdjLocked() 一参的流程之后,二参函数应该会简单些。相比于一参的函数,这里多了一个参数 app,这个是指定一个进程。该函数用以更新指定进程以及所有绑定(直接/间接)的其他进程的adj。如果该进程中拥有service 或content provider,则其client进程的procState将不会被重新评估。

    /*更新指定进程的 adj 等值,如果参数app为null,表示更新所有LRU 进程*/boolean updateOomAdjLocked(ProcessRecord app, String oomAdjReason) {// 如果传入的app 为null,表示全部 LRU 进程都更新if (app == null || !mConstants.OOMADJ_UPDATE_QUICK) {updateOomAdjLocked(oomAdjReason);return true;}// 从 AMS 中获取topAppfinal ProcessRecord topApp = mService.getTopAppLocked();Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, oomAdjReason);mService.mOomAdjProfiler.oomAdjStarted();// 用于标识 oom_adj 分配周期的id// 每次 updateOomAdjLocked() 函数调用都会有 mAdjSeq 序号,用以与进程adjSeq对比//    用以确认进程是否已经处理mAdjSeq++;// 第一步,更新进程自己// 确认是否处于 cached状态final boolean wasCached = app.isCached();// 获取当前 unlimit的adjfinal int oldAdj = app.getCurRawAdj();// 进而确认cached adjfinal int cachedAdj = oldAdj >= ProcessList.CACHED_APP_MIN_ADJ? oldAdj : ProcessList.UNKNOWN_ADJ;final boolean wasBackground = ActivityManager.isProcStateBackground(app.setProcState);app.containsCycle = false;app.procStateChanged = false;app.resetCachedInfo();// 调用 5参的函数,更新adjboolean success = updateOomAdjLocked(app, cachedAdj, topApp, false,SystemClock.uptimeMillis());// 是cached 进程并且background状态未变,但没有5参更新成功(进程被kill了)if (!success || (wasCached == app.isCached() && oldAdj != ProcessList.INVALID_ADJ&& wasBackground == ActivityManager.isProcStateBackground(app.setProcState))) {// Okay, it's unchanged, it won't impact any service it binds to, we're done here.if (DEBUG_OOM_ADJ) {Slog.i(TAG_OOM_ADJ, "No oomadj changes for " + app);}mService.mOomAdjProfiler.oomAdjEnded();Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);return success; // 返回失败}//第二步:找到所有的reachable进程, 更新reachable进程ArrayList<ProcessRecord> processes = mTmpProcessList;ActiveUids uids = mTmpUidRecords;//mTmpQueue:大小是两倍的 CUR_MAX_CACHED_PROCESSES = 32 ArrayDeque<ProcessRecord> queue = mTmpQueue;processes.clear();uids.clear();queue.clear();// Track if any of them reachables could include a cycleboolean containsCycle = false;// Scan downstreams of the process recordapp.mReachable = true;// 循环遍历reachable的进程,其实就是遍历有关联的service和provider// 第一个for循环执行的是app,此时queue为空,第一个for循环将app的所有相关联service和provider都加入到queue中// 之后的for循环就是遍历queue,即遍历reachable进程// poll:检索并移除队列的头部for (ProcessRecord pr = app; pr != null; pr = queue.poll()) {if (pr != app) {processes.add(pr);}if (pr.uidRecord != null) {uids.put(pr.uidRecord.uid, pr.uidRecord);}// 有连接相关的进程for (int i = pr.connections.size() - 1; i >= 0; i--) {ConnectionRecord cr = pr.connections.valueAt(i);ProcessRecord service = (cr.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0? cr.binding.service.isolatedProc : cr.binding.service.app;if (service == null || service == pr) {continue;}containsCycle |= service.mReachable;if (service.mReachable) {continue;}// BIND_WAIVE_PRIORITY: 不会影响服务的进程优先级,像通用的应用进程一样将服务放在一个LRU表中if ((cr.flags & (Context.BIND_WAIVE_PRIORITY| Context.BIND_TREAT_LIKE_ACTIVITY| Context.BIND_ADJUST_WITH_ACTIVITY))== Context.BIND_WAIVE_PRIORITY) {continue;}// 加入队列尾部queue.offer(service);service.mReachable = true;}for (int i = pr.conProviders.size() - 1; i >= 0; i--) {ContentProviderConnection cpc = pr.conProviders.get(i);ProcessRecord provider = cpc.provider.proc;if (provider == null || provider == pr || (containsCycle |= provider.mReachable)) {continue;}containsCycle |= provider.mReachable;if (provider.mReachable) {continue;}queue.offer(provider);provider.mReachable = true;}}// Reset the flagapp.mReachable = false;int size = processes.size();if (size > 0) {// Reverse the process list, since the updateOomAdjLockedInner scans from the end of it.for (int l = 0, r = size - 1; l < r; l++, r--) {ProcessRecord t = processes.get(l);processes.set(l, processes.get(r));processes.set(r, t);}mAdjSeq--;// 更新传入的进程列表,然后通过 updateOomAdjLockedInner()来更新这些进程updateOomAdjLockedInner(oomAdjReason, topApp, processes, uids, containsCycle, false);} else if (app.getCurRawAdj() == ProcessList.UNKNOWN_ADJ) {// In case the app goes from non-cached to cached but it doesn't have other reachable// processes, its adj could be still unknown as of now, assign one.processes.add(app);assignCachedAdjIfNecessary(processes);applyOomAdjLocked(app, false, SystemClock.uptimeMillis(),SystemClock.elapsedRealtime());}//统计系统进入计算OomAdj的起始和结束时间,最后计算出OomAdj的运行时间//  mOomAdjProfiler 这个类应该是用来统计所有OomAdj信息的,在AMS中有定义实例mService.mOomAdjProfiler.oomAdjEnded();Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);return true;}

9. updateOomAdjLocked() 三参

三参的函数比较简单,相比于二参函数,多了一个参数 oomAdjAll。如果该值为true,则与二参的流程一样;如果该值为 false,则直接调用五参函数进行直接更新。

    boolean updateOomAdjLocked(ProcessRecord app, boolean oomAdjAll,String oomAdjReason) {if (oomAdjAll && mConstants.OOMADJ_UPDATE_QUICK) {return updateOomAdjLocked(app, oomAdjReason);}final ProcessRecord TOP_APP = mService.getTopAppLocked();final boolean wasCached = app.isCached();mAdjSeq++;// This is the desired cached adjusment we want to tell it to use.// If our app is currently cached, we know it, and that is it.  Otherwise,// we don't know it yet, and it needs to now be cached we will then// need to do a complete oom adj.final int cachedAdj = app.getCurRawAdj() >= ProcessList.CACHED_APP_MIN_ADJ? app.getCurRawAdj() : ProcessList.UNKNOWN_ADJ;boolean success = updateOomAdjLocked(app, cachedAdj, TOP_APP, false,SystemClock.uptimeMillis());if (oomAdjAll&& (wasCached != app.isCached() || app.getCurRawAdj() == ProcessList.UNKNOWN_ADJ)) {// Changed to/from cached state, so apps after it in the LRU// list may also be changed.updateOomAdjLocked(oomAdjReason);}return success;}

10. updateOomAdjLocked() 五参

该函数是private 函数,会被二参函数和三参的函数调用,该函数只是更新某一个特定进程以及其关联进程,按照逻辑看参数doingAll 都被置为false。

    private final boolean updateOomAdjLocked(ProcessRecord app, int cachedAdj,ProcessRecord TOP_APP, boolean doingAll, long now) {if (app.thread == null) {return false;}// 重置cached infoapp.resetCachedInfo();// 获取进程所在用户组的整体状态,UidRecord用于记录某个用户组中进程的运行状态UidRecord uidRec = app.uidRecord;if (uidRec != null) {if (DEBUG_UID_OBSERVERS) {Slog.i(TAG_UID_OBSERVERS, "Starting update of " + uidRec);}uidRec.reset();}// 计算进程相关的adj,最后参数为true,即把client 进程也计算computeOomAdjLocked(app, cachedAdj, TOP_APP, doingAll, now, false, true);// 应用adjboolean success = applyOomAdjLocked(app, doingAll, now, SystemClock.elapsedRealtime());// 更新UidRecordif (uidRec != null) {// After uidRec.reset() above, for UidRecord that has multiple processes (ProcessRecord)// , We need to apply all ProcessRecord into UidRecord.final ArraySet<ProcessRecord> procRecords = app.uidRecord.procRecords;for (int i = procRecords.size() - 1; i >= 0; i--) {final ProcessRecord pr = procRecords.valueAt(i);if (!pr.killedByAm && pr.thread != null) {if (pr.isolated && pr.numberOfRunningServices() <= 0&& pr.isolatedEntryPoint == null) {// No op.} else {// Keeping this process, update its uid.updateAppUidRecLocked(pr);}}}if (uidRec.getCurProcState() != PROCESS_STATE_NONEXISTENT&& (uidRec.setProcState != uidRec.getCurProcState()|| uidRec.setCapability != uidRec.curCapability|| uidRec.setWhitelist != uidRec.curWhitelist)) {ActiveUids uids = mTmpUidRecords;uids.clear();uids.put(uidRec.uid, uidRec);updateUidsLocked(uids, now);mProcessList.incrementProcStateSeqAndNotifyAppsLocked(uids);}}return success;}

主要调用 computeOomAdjLocked() 和 applyOomAdjLocked(),详细可以查看《更新原理(二)》

11. updateOomAdjLockedInner()

frameworks/base/services/core/java/com/android/server/am/OomAdjuster.javaprivate void updateOomAdjLockedInner(String oomAdjReason, final ProcessRecord topApp,ArrayList<ProcessRecord> processes, ActiveUids uids, boolean potentialCycles,boolean startProfiling) {if (startProfiling) {Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, oomAdjReason);mService.mOomAdjProfiler.oomAdjStarted();}final long now = SystemClock.uptimeMillis();final long nowElapsed = SystemClock.elapsedRealtime();// 这里有个30mins的限制,如果activity 30分钟内没有活跃,后面会被kill掉final long oldTime = now - ProcessList.MAX_EMPTY_TIME;final boolean fullUpdate = processes == null;ActiveUids activeUids = uids;// 确定是否使用参数中传入的进程list,如果参数为NULL,则使用LRU processesArrayList<ProcessRecord> activeProcesses = fullUpdate ? mProcessList.mLruProcesses: processes;final int numProc = activeProcesses.size();// 确认传入的uid是否为NULL,如果是则用 mActiveUids初始化if (activeUids == null) {final int numUids = mActiveUids.size();activeUids = mTmpUidRecords;activeUids.clear();for (int i = 0; i < numUids; i++) {UidRecord r = mActiveUids.valueAt(i);activeUids.put(r.uid, r);}}// 重置用户组中所有进程的状态for (int  i = activeUids.size() - 1; i >= 0; i--) {final UidRecord uidRec = activeUids.valueAt(i);if (DEBUG_UID_OBSERVERS) {Slog.i(TAG_UID_OBSERVERS, "Starting update of " + uidRec);}uidRec.reset();}if (mService.mAtmInternal != null) {mService.mAtmInternal.rankTaskLayersIfNeeded();}// 用于标识 oom_adj 分配周期的id// 每次 updateOomAdjLocked() 函数调用都会有 mAdjSeq 序号,用以与进程adjSeq对比//    用以确认进程是否已经处理mAdjSeq++;if (fullUpdate) {mNewNumServiceProcs = 0;mNewNumAServiceProcs = 0;}boolean retryCycles = false;boolean computeClients = fullUpdate || potentialCycles;// 先进行一些 reset 工作for (int i = numProc - 1; i >= 0; i--) {ProcessRecord app = activeProcesses.get(i);//所有进程的reachable都改为falseapp.mReachable = false;// app.adjSeq会记录进程上一次的更新序号,如果已经评估过,后面就不会在计算if (app.adjSeq != mAdjSeq) {app.containsCycle = false;//设为 empty 进程app.setCurRawProcState(PROCESS_STATE_CACHED_EMPTY);//adj 设为UNKNOWN_ADJapp.setCurRawAdj(ProcessList.UNKNOWN_ADJ);app.setCapability = PROCESS_CAPABILITY_NONE;app.resetCachedInfo();}}// 进入compute 阶段for (int i = numProc - 1; i >= 0; i--) {ProcessRecord app = activeProcesses.get(i);if (!app.killedByAm && app.thread != null) {app.procStateChanged = false;computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, topApp, fullUpdate, now, false,computeClients); // It won't enter cycle if not computing clients.// if any app encountered a cycle, we need to perform an additional loop laterretryCycles |= app.containsCycle;// Keep the completedAdjSeq to up to date.app.completedAdjSeq = mAdjSeq;}}//将 cache 进程和 empty 进程均匀分散到slot中去assignCachedAdjIfNecessary(mProcessList.mLruProcesses);//是否需要计算进程绑定的client的adj,同时一参调用是需要计算的if (computeClients) { // There won't be cycles if we didn't compute clients above.// Cycle strategy:// - Retry computing any process that has encountered a cycle.// - Continue retrying until no process was promoted.// - Iterate from least important to most important.int cycleCount = 0;while (retryCycles && cycleCount < 10) {cycleCount++;retryCycles = false;for (int i = 0; i < numProc; i++) {ProcessRecord app = activeProcesses.get(i);if (!app.killedByAm && app.thread != null && app.containsCycle) {app.adjSeq--;app.completedAdjSeq--;}}for (int i = 0; i < numProc; i++) {ProcessRecord app = activeProcesses.get(i);if (!app.killedByAm && app.thread != null && app.containsCycle) {if (computeOomAdjLocked(app, app.getCurRawAdj(), topApp, true, now,true, true)) {retryCycles = true;}}}}}// 非cached或empty进程数置0mNumNonCachedProcs = 0;// cached hidden进程数置0mNumCachedHiddenProcs = 0;// 杀掉超过限额的empty进程和cached进程,这个函数很重要boolean allChanged = updateAndTrimProcessLocked(now, nowElapsed, oldTime, activeUids);mNumServiceProcs = mNewNumServiceProcs;if (mService.mAlwaysFinishActivities) {// Need to do this on its own message because the stack may not// be in a consistent state at this point.mService.mAtmInternal.scheduleDestroyAllActivities("always-finish");}if (allChanged) {mService.requestPssAllProcsLocked(now, false,mService.mProcessStats.isMemFactorLowered());}updateUidsLocked(activeUids, nowElapsed);if (mService.mProcessStats.shouldWriteNowLocked(now)) {mService.mHandler.post(new ActivityManagerService.ProcStatsRunnable(mService,mService.mProcessStats));}// Run this after making sure all procstates are updated.mService.mProcessStats.updateTrackingAssociationsLocked(mAdjSeq, now);if (DEBUG_OOM_ADJ) {final long duration = SystemClock.uptimeMillis() - now;if (false) {Slog.d(TAG_OOM_ADJ, "Did OOM ADJ in " + duration + "ms",new RuntimeException("here").fillInStackTrace());} else {Slog.d(TAG_OOM_ADJ, "Did OOM ADJ in " + duration + "ms");}}if (startProfiling) {mService.mOomAdjProfiler.oomAdjEnded();Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);}}

11.1 assignCachedAdjIfNecessary()

    /**该函数是将lru list中的cache的进程按照一定的跨距逐个分配到[CACHED_APP_MIN_ADJ, CACHED_APP_MAX_ADJ]区间中*根据proc_state为empty和其他cached,对其进行分配*/private void assignCachedAdjIfNecessary(ArrayList<ProcessRecord> lruList) {final int numLru = lruList.size();// 首先,根据进程当前状态为每个进程更新oom adjint curCachedAdj = ProcessList.CACHED_APP_MIN_ADJ;int nextCachedAdj = curCachedAdj + (ProcessList.CACHED_APP_IMPORTANCE_LEVELS * 2);int curCachedImpAdj = 0;int curEmptyAdj = ProcessList.CACHED_APP_MIN_ADJ + ProcessList.CACHED_APP_IMPORTANCE_LEVELS;int nextEmptyAdj = curEmptyAdj + (ProcessList.CACHED_APP_IMPORTANCE_LEVELS * 2);final int emptyProcessLimit = mConstants.CUR_MAX_EMPTY_PROCESSES;final int cachedProcessLimit = mConstants.CUR_MAX_CACHED_PROCESSES- emptyProcessLimit;//计算出槽的数量,再将cache进程和empty进程分别平均分配到这些槽中(slots)//  CACHED_APP_MIN_ADJ ~ CACHED_APP_MAX_ADJ 之间交错分配cached和empty进程//  mNumNonCachedProcs 是除cached进程外的进程数,mNumCachedHiddenProcs是cached进程个数int numEmptyProcs = numLru - mNumNonCachedProcs - mNumCachedHiddenProcs;if (numEmptyProcs > cachedProcessLimit) { //空进程数大于cache进程阈值//确保低内存杀进程的时候以杀empty为主,尽可能保留cachenumEmptyProcs = cachedProcessLimit;}//cachedFactor和emptyFactor分别表示每个slot中包括的进程个数int cachedFactor = (mNumCachedHiddenProcs > 0 ? (mNumCachedHiddenProcs + mNumSlots - 1) : 1)/ mNumSlots;if (cachedFactor < 1) cachedFactor = 1;int emptyFactor = (numEmptyProcs + mNumSlots - 1) / mNumSlots;if (emptyFactor < 1) emptyFactor = 1;int stepCached = -1;int stepEmpty = -1;int lastCachedGroup = 0;int lastCachedGroupImportance = 0;int lastCachedGroupUid = 0;//遍历lru列表,为每一个app进程更新cache状态for (int i = numLru - 1; i >= 0; i--) {ProcessRecord app = lruList.get(i);// If we haven't yet assigned the final cached adj// to the process, do that now.if (!app.killedByAm && app.thread != null && app.curAdj>= ProcessList.UNKNOWN_ADJ) {switch (app.getCurProcState()) { //三种非empty cache进程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.boolean inGroup = false;if (app.connectionGroup != 0) {if (lastCachedGroupUid == app.uid&& lastCachedGroup == app.connectionGroup) {// This is in the same group as the last process, just tweak// adjustment by importance.if (app.connectionImportance > lastCachedGroupImportance) {lastCachedGroupImportance = app.connectionImportance;if (curCachedAdj < nextCachedAdj&& curCachedAdj < ProcessList.CACHED_APP_MAX_ADJ) {curCachedImpAdj++;}}inGroup = true;} else {lastCachedGroupUid = app.uid;lastCachedGroup = app.connectionGroup;lastCachedGroupImportance = app.connectionImportance;}}//当前slot数大于factor,分配下一个slot,更新cur和next的cachedadjif (!inGroup && curCachedAdj != nextCachedAdj) {stepCached++;curCachedImpAdj = 0;if (stepCached >= cachedFactor) {stepCached = 0;curCachedAdj = nextCachedAdj;nextCachedAdj += ProcessList.CACHED_APP_IMPORTANCE_LEVELS * 2;if (nextCachedAdj > ProcessList.CACHED_APP_MAX_ADJ) {nextCachedAdj = ProcessList.CACHED_APP_MAX_ADJ;}}}// This process is a cached process holding activities...// assign it the next cached value for that type, and then// step that cached level.app.setCurRawAdj(curCachedAdj + curCachedImpAdj);app.curAdj = app.modifyRawOomAdj(curCachedAdj + curCachedImpAdj);if (DEBUG_LRU) {Slog.d(TAG_LRU, "Assigning activity LRU #" + i+ " adj: " + app.curAdj + " (curCachedAdj=" + curCachedAdj+ " curCachedImpAdj=" + curCachedImpAdj + ")");}break;default: //empty进程// Figure out the next cached level.if (curEmptyAdj != nextEmptyAdj) {stepEmpty++;if (stepEmpty >= emptyFactor) {stepEmpty = 0;curEmptyAdj = nextEmptyAdj;nextEmptyAdj += ProcessList.CACHED_APP_IMPORTANCE_LEVELS * 2;if (nextEmptyAdj > ProcessList.CACHED_APP_MAX_ADJ) {nextEmptyAdj = ProcessList.CACHED_APP_MAX_ADJ;}}}// For everything else, assign next empty cached process// level and bump that up.  Note that this means that// long-running services that have dropped down to the// cached level will be treated as empty (since their process// state is still as a service), which is what we want.app.setCurRawAdj(curEmptyAdj);app.curAdj = app.modifyRawOomAdj(curEmptyAdj);if (DEBUG_LRU) {Slog.d(TAG_LRU, "Assigning empty LRU #" + i+ " adj: " + app.curAdj + " (curEmptyAdj=" + curEmptyAdj+ ")");}break;}}}}

AMS将所有cache和empty按照一定的机制均分到[900,999]区间中;在这个区间中,每一个分配给cache/empty进程的adj值都被称为一个槽点(slot),实际上是将LRU列表中的所有cache进程按照一定的跨距均分到这些槽点中;

在这个机制里面,cache进程的adj分配起点为900,而empty进程的分配起点为905,两者都是以跨距为10进行均匀分配的;这样就能够将empty进程和cache进程分开,彼此间隔相同的距离。当内存不足时,lmkd进程就会从adj最大值开始,逐步往下查杀进程,不会出现集体被杀或者都不被杀导致内存占用过高的问题。

注意:

临时变量 emptyProcessLimit 记录系统中empty进程的最大值,通常为 cached 最大值的一半,即默认值为32/2 = 16;

临时变量 cachedProcessLimit 记录系统中cached 进程的最大值,即mConstants.CUR_MAX_CACHED_PROCESSES - emptyProcessLimit,CUR_MAX_CACHED_PROCESSES  默认为32,减去 emptyProcessLimit,剩余也是16个;

11.2 updateAndTrimProcessLocked()

    private boolean updateAndTrimProcessLocked(final long now, final long nowElapsed,final long oldTime, final ActiveUids activeUids) {ArrayList<ProcessRecord> lruList = mProcessList.mLruProcesses;final int numLru = lruList.size();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;/*******针对 B service 优化的地方 1*******/ProcessRecord selectedAppRecord = null;long serviceLastActivity = 0;int numBServices = 0;/*******针对 B service 优化的地方 1 end*******/// 反向遍历 LRUfor (int i = numLru - 1; i >= 0; i--) {ProcessRecord app = lruList.get(i);/*******针对 B service 优化的地方 2*******/if (mEnableBServicePropagation && app.serviceb&& (app.curAdj == ProcessList.SERVICE_B_ADJ)) {numBServices++;// 遍历正在运行的服务for (int s = app.numberOfRunningServices() - 1; s >= 0; s--) {ServiceRecord sr = app.getRunningServiceAt(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);// 当前时间与上一次activity运行该服务的时间差,lastActivity在创建services时更新// mMinBServiceAgingTime = 5000ms,B_service的最小老化时间阈值if (SystemClock.uptimeMillis() - sr.lastActivity< mMinBServiceAgingTime) {if (DEBUG_OOM_ADJ) {Slog.d(TAG,"Not aged enough!!!");}continue;}// 更新距上一次运行service 的时间最久的app// 当进程为 B_service,在B_service进程数超过阈值(5个)时,// 如果该进程相关联的service 中,有最久未被调用的service,则将该进程设置//    为SelectedAppRecord,将其adj设置为800,lmkd中存储的是900if (serviceLastActivity == 0) {serviceLastActivity = sr.lastActivity;selectedAppRecord = app;} else if (sr.lastActivity < serviceLastActivity) {serviceLastActivity = sr.lastActivity;selectedAppRecord = app;}}}if (DEBUG_OOM_ADJ && selectedAppRecord != null) Slog.d(TAG,"Identified app.processName = " + selectedAppRecord.processName+ " app.pid = " + selectedAppRecord.pid);/*******针对 B service 优化的地方 2 end*******/if (!app.killedByAm && app.thread != null) {//  不需要为没有计算的进程应用更新if (app.completedAdjSeq == mAdjSeq) {applyOomAdjLocked(app, true, now, nowElapsed);}// 根据procState 确定进程类型数量switch (app.getCurProcState()) {case PROCESS_STATE_CACHED_ACTIVITY: //处理cached 且函数activity的进程case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:mNumCachedHiddenProcs++; //统计cached进程个数numCached++;if (app.connectionGroup != 0) {if (lastCachedGroupUid == app.info.uid&& lastCachedGroup == app.connectionGroup) {// 如果与上一个进程同一个进程组,//   不希望它与cached 进程数量限制相冲突,只是//   额外增加group count来统计numCachedExtraGroup++;} else {lastCachedGroupUid = app.info.uid;lastCachedGroup = app.connectionGroup;}} else {lastCachedGroupUid = lastCachedGroup = 0;}// 除掉额外计数的cached进程,扔超过limit的,killif ((numCached - numCachedExtraGroup) > cachedProcessLimit) {app.kill("cached #" + numCached,ApplicationExitInfo.REASON_OTHER,ApplicationExitInfo.SUBREASON_TOO_MANY_CACHED,true);}break;case PROCESS_STATE_CACHED_EMPTY: //处理被cached 的empty进程//当empty进程超过CUR_TRIM_EMPTY_PROCESSES(默认8个),// 并且activity上次活跃超过了30min,killif (numEmpty > mConstants.CUR_TRIM_EMPTY_PROCESSES&& app.lastActivityTime < oldTime) {app.kill("empty for "+ ((oldTime + ProcessList.MAX_EMPTY_TIME - app.lastActivityTime)/ 1000) + "s",ApplicationExitInfo.REASON_OTHER,ApplicationExitInfo.SUBREASON_TRIM_EMPTY,true);} else {numEmpty++;// empty 进程中activity虽然没有超过30min,但总的数量超过了16(默认值),killif (numEmpty > emptyProcessLimit) {app.kill("empty #" + numEmpty,ApplicationExitInfo.REASON_OTHER,ApplicationExitInfo.SUBREASON_TOO_MANY_EMPTY,true);}}break;default:mNumNonCachedProcs++;break;}// 如果该进程是isolated,其中没有运行service,并且它不是具有自定义入口点的特殊//    进程,那么该进程就不再需要了。// 我们强烈地杀掉这些进程因为我们可以根据定义不再重复使用相同的进程,这样能够很好//  地避免在不再需要的情况下让代码中的任何代码在它们中运行。if (app.isolated && app.numberOfRunningServices() <= 0&& app.isolatedEntryPoint == 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.kill("isolated not needed", ApplicationExitInfo.REASON_OTHER,ApplicationExitInfo.SUBREASON_ISOLATED_NOT_NEEDED, true);} else {// 否则就保留这些进程,//更新进程的 uidRecordupdateAppUidRecLocked(app);}if (app.getCurProcState() >= ActivityManager.PROCESS_STATE_HOME&& !app.killedByAm) {numTrimming++;}}}/*******针对 B service 优化的地方 3*******/// 当B_Service 的数量超过上面(mBServiceAppThreshold=5),// 且mAllowLowerMemLevel 为true,即为低内存lmkd 杀过进程if ((numBServices > mBServiceAppThreshold) && (true == mService.mAllowLowerMemLevel)&& (selectedAppRecord != null)) {// setOomAdj() 方法是将更新后的 adj通知给 lmkdProcessList.setOomAdj(selectedAppRecord.pid, selectedAppRecord.info.uid,ProcessList.CACHED_APP_MAX_ADJ);//将最久没运行过的appRecord的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");}/*******针对 B service 优化的地方 3 end*******/mProcessList.incrementProcStateSeqAndNotifyAppsLocked(activeUids);//本方法根据cached和empty进程的数量,确定 memFactor;根据memFactor是否为NORMAL等级分别进行处理return mService.updateLowMemStateLocked(numCached, numEmpty, numTrimming);}

updateAndTrimProcessLocked() 包含了很多 app.kill() 方法,是 AMS 除了lmkd 之外的一个查杀进程机制。该函数中遍历 LRU 列表,分别统计 cached 和 empty 进程,并进行trim 处理。对超过限定的 cached 和 empty 进程进行查杀,回收内存。

其中临时变量 emptyProcessLimit 和 cachedProcessLimit 分别记录empty 进程和 cached 进程个数的上限,同 assignCachedAdjIfNecessary() 函数中,这里两个值默认都是 16.

另外,该函数中在源生的基础上添加了针对 B_services 优化点,共 3 处,如代码中的注释。其中涉及到的变量mMinBServiceAgingTime、mBServiceAppThreshold、mEnableBServicePropagation 都是在 OomAdjuster.java 中定义的成员变量。详细的patch,可以下载

11.2.1 updateLowMemStateLocked()

frameworks/base/services/core/java/com/android/server/am/AMS.java/**
*本方法根据cached和empty进程的数量,确定 memFactor;根据memFactor是否为NORMAL等级分别进行处理
* 1、非NORMAL:将memFactor转换为trim level等级,根据当前进程的进程级别分等级处理,确定最新的trim level
* 2、NORMAL:对于重要性比IMPORTANT_BACKGROUND小或没有运行UI的system进程,关闭其从showing UI回收内存的权利,并且将trimlevel提升到不低于UI_HIDDEN
*/
final boolean updateLowMemStateLocked(int numCached, int numEmpty, int numTrimming) {final int N = mProcessList.getLruSizeLocked();//lru大小final long now = SystemClock.uptimeMillis();//内存因子,值越大,级别越高,内存资源越紧张int memFactor;if (mLowMemDetector != null && mLowMemDetector.isAvailable()) {//获取memfactor,此函数根据PSI event返回对应的内存因子级别,通过监听/proc/pressure/memory实现// waitforPressure方法是一个jni调用memFactor = mLowMemDetector.getMemFactor();} else {// R上不在使用// 根据cache进程和empty进程的个数得出memfactor,memfactor越大,内存压力越大if (numCached <= mConstants.CUR_TRIM_CACHED_PROCESSES//32/6=5&& numEmpty <= mConstants.CUR_TRIM_EMPTY_PROCESSES) {//8final int numCachedAndEmpty = numCached + numEmpty;if (numCachedAndEmpty <= ProcessList.TRIM_CRITICAL_THRESHOLD) {//3memFactor = ProcessStats.ADJ_MEM_FACTOR_CRITICAL;} else if (numCachedAndEmpty <= ProcessList.TRIM_LOW_THRESHOLD) {//5memFactor = ProcessStats.ADJ_MEM_FACTOR_LOW;} else {memFactor = ProcessStats.ADJ_MEM_FACTOR_MODERATE;}} else {memFactor = ProcessStats.ADJ_MEM_FACTOR_NORMAL;}}// We always allow the memory level to go up (better).  We only allow it to go// down if we are in a state where that is allowed, *and* the total number of processes// has gone down since last time.if (DEBUG_OOM_ADJ) Slog.d(TAG_OOM_ADJ, "oom: memFactor=" + memFactor+ " last=" + mLastMemoryLevel + " allowLow=" + mAllowLowerMemLevel+ " numProcs=" + mProcessList.getLruSizeLocked() + " last=" + mLastNumProcesses);//现在的等级比之前还高,说明内存紧张,不主动降低等级if (memFactor > mLastMemoryLevel) {//当不允许LowerMemLevel或者LRU进程数有增加时,可以降低等级if (!mAllowLowerMemLevel || mProcessList.getLruSizeLocked() >= mLastNumProcesses) {memFactor = mLastMemoryLevel;if (DEBUG_OOM_ADJ) Slog.d(TAG_OOM_ADJ, "Keeping last mem factor!");}}//内存因子更新了if (memFactor != mLastMemoryLevel) {EventLogTags.writeAmMemFactor(memFactor, mLastMemoryLevel);FrameworkStatsLog.write(FrameworkStatsLog.MEMORY_FACTOR_STATE_CHANGED, memFactor);}//更新最近一次memorylevel的等级mLastMemoryLevel = memFactor;mLastNumProcesses = mProcessList.getLruSizeLocked();//将内存等级保存到processstats中,如果与之前不等(更新了),返回trueboolean allChanged = mProcessStats.setMemFactorLocked(memFactor, mAtmInternal != null ? !mAtmInternal.isSleeping() : true, now);//更新后获取factorfinal int trackerMemFactor = mProcessStats.getMemFactorLocked();//下面为两个大判断,memFactor 为NORMAL和不为NORMAL两种情况//memFactor 不等于NORMAL时的处理if (memFactor != ProcessStats.ADJ_MEM_FACTOR_NORMAL) {if (mLowRamStartTime == 0) {//进入lowRam状态,记录进入的时间点mLowRamStartTime = now;}int step = 0;int fgTrimLevel;//将内存因子memFactor转换为ComponentCallbacks2中定义的变量名,//就是从memFactor等级转换到 TrimMemlevel//TrimMemlevel 值越大越容易被回收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;}//factor为每个槽可以容纳的进程数// 三个LowRam状态各自放多少Trimming进程int factor = numTrimming/3;int minFactor = 2;if (mAtmInternal.getHomeProcess() != null) minFactor++;if (mAtmInternal.getPreviousProcess() != null) minFactor++;if (factor < minFactor) factor = minFactor;//80,最高等级,内存压力最大int curLevel = ComponentCallbacks2.TRIM_MEMORY_COMPLETE;// 对于重要性大于home的进程而言,重要性越高,内存回收等级越低// 对于重要性小于home的进程,排在LRU列表越靠后,即越重要回收等级越高// 这么安排的理由有两个:// 1、此时越不重要的进程,其中运行的组件越少,能够回收的内存不多,不需要高回收等级// 2、越不重要的进程越有可能被LMK kill掉,没必要以高等级回收内存//反向遍历LRU链表for (int i=N-1; i>=0; i--) {ProcessRecord app = mProcessList.mLruProcesses.get(i);if (allChanged || app.procStateChanged) {setProcessTrackerStateLocked(app, trackerMemFactor, now);app.procStateChanged = false;}//process_state大于等于HOME进程,没HOME这么重要的进程if (app.getCurProcState() >= ActivityManager.PROCESS_STATE_HOME&& !app.killedByAm) {if (app.trimMemoryLevel < curLevel && app.thread != null) {try {//加大内存回收app.thread.scheduleTrimMemory(curLevel);} catch (RemoteException e) {}}//调整 trimMemoryLevel 到 curlevelapp.trimMemoryLevel = curLevel;step++;//当前factor满了,下一个factorif (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;}}} else if (app.getCurProcState() == ActivityManager.PROCESS_STATE_HEAVY_WEIGHT&& !app.killedByAm) {//重量级后台进程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);//level提到TRIM_MEMORY_BACKGROUNDapp.thread.scheduleTrimMemory(ComponentCallbacks2.TRIM_MEMORY_BACKGROUND);} catch (RemoteException e) {}}app.trimMemoryLevel = ComponentCallbacks2.TRIM_MEMORY_BACKGROUND;} else {//其他进程级别//级别大于等于重要的后台进程if ((app.getCurProcState() >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND|| app.systemNoUi) && app.hasPendingUiClean()) {// If this application is now in the background and it// had done UI, then give it the special trim level to// have it free UI resources.final int level = ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN;if (app.trimMemoryLevel < level && app.thread != null) {try {//回收app.thread.scheduleTrimMemory(level);} catch (RemoteException e) {}}app.setPendingUiClean(false);}if (app.trimMemoryLevel < fgTrimLevel && app.thread != null) {try {//关掉showingUI回收app.thread.scheduleTrimMemory(fgTrimLevel);} catch (RemoteException e) {}}app.trimMemoryLevel = fgTrimLevel;}}} else { //memFactor == NORMAL时的处理if (mLowRamStartTime != 0) {//统计总的LowRam持续时间mLowRamTimeSinceLastIdle += now - mLowRamStartTime;//NORMAL状态取消LowRam状态和计时mLowRamStartTime = 0;}for (int i=N-1; i>=0; i--) {ProcessRecord app = mProcessList.mLruProcesses.get(i);if (allChanged || app.procStateChanged) {setProcessTrackerStateLocked(app, trackerMemFactor, now);app.procStateChanged = false;}//当前内存factor是NORMAL,根据当前进程state和trimmemorylevel,// 关掉showingUI回收(只处理比PROCESS_STATE_IMPORTANT_BACKGROUND不重要的进程)//PROCESS_STATE_IMPORTANT_BACKGROUND重要的后台进程// systemNoUi:系统进程但是没有正在显示的UI;hasPendingUiClean:是否想从showingUI回收内存if ((app.getCurProcState() >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND|| app.systemNoUi) && app.hasPendingUiClean()) {//内存等级小于TRIM_MEMORY_UI_HIDDENif (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN&& app.thread != null) {try {//调整TrimMemoryLevel到TRIM_MEMORY_UI_HIDDENapp.thread.scheduleTrimMemory(ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);} catch (RemoteException e) {}}//清理showingUI:falseapp.setPendingUiClean(false);}app.trimMemoryLevel = 0;}}return allChanged;}

接下一篇:Android oom_adj 更新原理(二)

这篇关于Android oom_adj 更新原理(一)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/700341

相关文章

Java编译生成多个.class文件的原理和作用

《Java编译生成多个.class文件的原理和作用》作为一名经验丰富的开发者,在Java项目中执行编译后,可能会发现一个.java源文件有时会产生多个.class文件,从技术实现层面详细剖析这一现象... 目录一、内部类机制与.class文件生成成员内部类(常规内部类)局部内部类(方法内部类)匿名内部类二、

Android中Dialog的使用详解

《Android中Dialog的使用详解》Dialog(对话框)是Android中常用的UI组件,用于临时显示重要信息或获取用户输入,本文给大家介绍Android中Dialog的使用,感兴趣的朋友一起... 目录android中Dialog的使用详解1. 基本Dialog类型1.1 AlertDialog(

Python中随机休眠技术原理与应用详解

《Python中随机休眠技术原理与应用详解》在编程中,让程序暂停执行特定时间是常见需求,当需要引入不确定性时,随机休眠就成为关键技巧,下面我们就来看看Python中随机休眠技术的具体实现与应用吧... 目录引言一、实现原理与基础方法1.1 核心函数解析1.2 基础实现模板1.3 整数版实现二、典型应用场景2

Java的IO模型、Netty原理解析

《Java的IO模型、Netty原理解析》Java的I/O是以流的方式进行数据输入输出的,Java的类库涉及很多领域的IO内容:标准的输入输出,文件的操作、网络上的数据传输流、字符串流、对象流等,这篇... 目录1.什么是IO2.同步与异步、阻塞与非阻塞3.三种IO模型BIO(blocking I/O)NI

MySQL新增字段后Java实体未更新的潜在问题与解决方案

《MySQL新增字段后Java实体未更新的潜在问题与解决方案》在Java+MySQL的开发中,我们通常使用ORM框架来映射数据库表与Java对象,但有时候,数据库表结构变更(如新增字段)后,开发人员可... 目录引言1. 问题背景:数据库与 Java 实体不同步1.1 常见场景1.2 示例代码2. 不同操作

Android Kotlin 高阶函数详解及其在协程中的应用小结

《AndroidKotlin高阶函数详解及其在协程中的应用小结》高阶函数是Kotlin中的一个重要特性,它能够将函数作为一等公民(First-ClassCitizen),使得代码更加简洁、灵活和可... 目录1. 引言2. 什么是高阶函数?3. 高阶函数的基础用法3.1 传递函数作为参数3.2 Lambda

Android自定义Scrollbar的两种实现方式

《Android自定义Scrollbar的两种实现方式》本文介绍两种实现自定义滚动条的方法,分别通过ItemDecoration方案和独立View方案实现滚动条定制化,文章通过代码示例讲解的非常详细,... 目录方案一:ItemDecoration实现(推荐用于RecyclerView)实现原理完整代码实现

Android App安装列表获取方法(实践方案)

《AndroidApp安装列表获取方法(实践方案)》文章介绍了Android11及以上版本获取应用列表的方案调整,包括权限配置、白名单配置和action配置三种方式,并提供了相应的Java和Kotl... 目录前言实现方案         方案概述一、 androidManifest 三种配置方式

一文详解SQL Server如何跟踪自动统计信息更新

《一文详解SQLServer如何跟踪自动统计信息更新》SQLServer数据库中,我们都清楚统计信息对于优化器来说非常重要,所以本文就来和大家简单聊一聊SQLServer如何跟踪自动统计信息更新吧... SQL Server数据库中,我们都清楚统计信息对于优化器来说非常重要。一般情况下,我们会开启"自动更新

JAVA封装多线程实现的方式及原理

《JAVA封装多线程实现的方式及原理》:本文主要介绍Java中封装多线程的原理和常见方式,通过封装可以简化多线程的使用,提高安全性,并增强代码的可维护性和可扩展性,需要的朋友可以参考下... 目录前言一、封装的目标二、常见的封装方式及原理总结前言在 Java 中,封装多线程的原理主要围绕着将多线程相关的操