本文主要是介绍android 内存管理之adj 《三》,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
概述
1.1 oom_adj与oom_score_adj
Android系统的设计理念正是希望应用进程能尽量长时间地存活,以提升用户体验。因此当应用推入到后台的时候进程并不会被立即杀死,而是存活一段时间,这样下次再使用则会非常快。但是如果处于后台的进程过多导致内存不足,此时就必须有选择的杀死部分进程。
到底该回收哪个进程呢?那么需要一个能管理所有进程,根据一定策略来释放进程的策略,这便有了lmk
,全称为LowMemoryKiller(低内存杀手),lmkd来决定什么时间杀掉什么进程。
系统根据进程的组件状态来决定每个进程的优先级值oom_adj,oom_adj 是 lmkd 内部定义的一个变量,其余oom_adj 存在一个映射关系,Android 7.0之前的版本,oom_score_adj= oom_adj * 1000/17; 而Android 7.0开始,oom_score_adj= oom_adj,不用再经过一次转换。
lmkd 主要是通过进程的oom_score_adj来判定进程的重要程度,其会按照oom_score_adj由大到小的顺序 杀死进程,依此类推,以回收预期的可用系统资源,从而保证系统正常运转。
1.2 ADJ 级别
ADJ级别 | 取值 | 含义 |
---|---|---|
NATIVE_ADJ | -1000 | native进程 |
SYSTEM_ADJ | -900 | 仅指system_server进程 |
PERSISTENT_PROC_ADJ | -800 | 系统persistent进程 |
PERSISTENT_SERVICE_ADJ | -700 | 关联着系统或persistent进程 |
FOREGROUND_APP_ADJ | 0 | 前台进程 |
VISIBLE_APP_ADJ | 100 | 可见进程 |
PERCEPTIBLE_APP_ADJ | 200 | 可感知进程,比如后台音乐播放 |
BACKUP_APP_ADJ | 300 | 备份进程 |
HEAVY_WEIGHT_APP_ADJ | 400 | 重量级进程 |
SERVICE_ADJ | 500 | 服务进程 |
HOME_APP_ADJ | 600 | Home进程 |
PREVIOUS_APP_ADJ | 700 | 上一个进程 |
SERVICE_B_ADJ | 800 | B List中的Service |
CACHED_APP_MIN_ADJ | 900 | 不可见进程的adj最小值 |
CACHED_APP_MAX_ADJ | 906 | 不可见进程的adj最大值 |
从Android 7.0开始,ADJ采用100、200、300;在这之前的版本ADJ采用数字1、2、3,这样的调整可以更进一步地细化进程的优先级,比如在VISIBLE_APP_ADJ(100)与PERCEPTIBLE_APP_ADJ(200)之间,可以有ADJ=101、102级别的进程。
A-Service与B-Service的划分
所有启动了服务的进程,且该服务所在的进程没有显示过UI,且该服务未执行startForeground(执行后会变为perveptible服务)动作,那该进程则为A-Service与B-Service中的一种。然后根据这类服务进程所处于Lru进程表中的位置,前1/3点服务为A-Service,其余的则为B-Service。
perceptible的标准
perceptible名为可感知的进程,但并不是说能够感知到进程就一定表示该进程属于perveptible进程,比如播放音乐的进程活着状态栏上有通知的进程,虽然能够感知到进程的存在,但是不代表进程一定时perceptible类别的进程。决定该进程是否属于perceptible进程并未进程的可感知性,而是该进程的服务是否执行了startForeground动作。
1.3 computeOomAdjLocked
第一部分
private final int computeOomAdjLocked(ProcessRecord app, int cachedAdj, ProcessRecord TOP_APP,boolean doingAll, long now) {
// updateOomAdjLocked函数每次更新oom_adj时,都会分配一个序号//此处就是根据序号判断是否已经处理过命令if (mAdjSeq == app.adjSeq) {// This adjustment has already been computed.return app.curRawAdj;}//设置empty进程adjif (app.thread == null) {app.adjSeq = mAdjSeq;app.curSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;//空进程app.curProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;return (app.curAdj=app.curRawAdj=ProcessList.CACHED_APP_MAX_ADJ);}//初始化一些变量//这些变量的具体用途,我们不关注//大家只用留意一下ProcessRecord的schedGroup、procState和oom_adj即可app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;app.adjSource = null;app.adjTarget = null;app.empty = false;app.cached = false;final int activitiesSize = app.activities.size();//初始化ProcessRecord maxAdjUNKNOWN_ADJ,//maxAdj取值为UNKNOWN_ADJ,即最大的1001//但是应该是只有系统进程才有可能进入这个分支。系统进程走完这个分支就返回了if (app.maxAdj <= ProcessList.FOREGROUND_APP_ADJ) {//adjType 跟cpu的调度权限有关系app.adjType = "fixed";app.adjSeq = mAdjSeq;app.curRawAdj = app.maxAdj;app.foregroundActivities = false;app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;app.curProcState = ActivityManager.PROCESS_STATE_PERSISTENT;//// System processes can do UI, and when they do we want to have// them trim their memory after the user leaves the UI. To// facilitate this, here we need to determine whether or not it// is currently showing UI.app.systemNoUi = true;if (app == TOP_APP) {app.systemNoUi = false;} else if (activitiesSize > 0) {for (int j = 0; j < activitiesSize; j++) {final ActivityRecord r = app.activities.get(j);if (r.visible) {app.systemNoUi = false;}}}if (!app.systemNoUi) {//系统进程有ui的时候app.curProcState = ActivityManager.PROCESS_STATE_PERSISTENT_UI;}//return (app.curAdj=app.maxAdj);}app.systemNoUi = false;//xxx
}
第一部分主要是更新了empty 进程与系统进程的curProcState。
第二部分
// Determine the importance of the process, starting with most// important to least, and assign an appropriate OOM adjustment.int adj;int schedGroup;int procState;boolean foregroundActivities = false;BroadcastQueue queue;if (app == TOP_APP) {//若进程包含正在前台显示的Activityadj = ProcessList.FOREGROUND_APP_ADJ;//schedGroup = Process.THREAD_GROUP_DEFAULT;app.adjType = "top-activity";foregroundActivities = true;procState = ActivityManager.PROCESS_STATE_TOP;} else if (app.instrumentationClass != null) {// Don't want to kill running instrumentation.adj = ProcessList.FOREGROUND_APP_ADJ;schedGroup = Process.THREAD_GROUP_DEFAULT;app.adjType = "instrumentation";procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;} else if ((queue = isReceivingBroadcast(app)) != null) {// An app that is currently receiving a broadcast also// counts as being in the foreground for OOM killer purposes.// It's placed in a sched group based on the nature of the// broadcast as reflected by which queue it's active in.adj = ProcessList.FOREGROUND_APP_ADJ;schedGroup = (queue == mFgBroadcastQueue)? Process.THREAD_GROUP_DEFAULT : Process.THREAD_GROUP_BG_NONINTERACTIVE;app.adjType = "broadcast";procState = ActivityManager.PROCESS_STATE_RECEIVER;} else if (app.executingServices.size() > 0) {// An app that is currently executing a service callback also// counts as being in the foreground.adj = ProcessList.FOREGROUND_APP_ADJ;schedGroup = app.execServicesFg ?Process.THREAD_GROUP_DEFAULT : Process.THREAD_GROUP_BG_NONINTERACTIVE;app.adjType = "exec-service";procState = ActivityManager.PROCESS_STATE_SERVICE;//Slog.i(TAG, "EXEC " + (app.execServicesFg ? "FG" : "BG") + ": " + app);} else {// As far as we know the process is empty. We may change our mind later.schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;// At this point we don't actually know the adjustment. Use the cached adj// value that the caller wants us to.//这一句很重要,除了上面几种情形,先设置adj为cacheAdj,也即是UNKNOWN_ADJadj = cachedAdj;//表明此时进程处于后台procState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;app.cached = true;app.empty = true;app.adjType = "cch-empty";}
上述几个分支除了最后的else 分支其余的adj都是FOREGROUND_APP_ADJ,但是schedGroup与procState 不同,也就是cpu资源调度是不一样的。当进程正在显示或者正在测试或者正在执行Service 或者正在执行Receiver的时候此时设置adj 为FOREGROUND_APP_ADJ。FOREGROUND_APP_ADJ 实际是0,比他小的都是adj一般表示的都是系统进程,因此FOREGROUND_APP_ADJ 可以看成是普通用户可以使用的最高的adj,用于这个adj的进程内存几乎不会被回收。最后的else 分支是将先将adj 设置为cachedAdj,此处cachedAdj 为UNKNOWN_ADJ,实际就是在后面再根据情况决定adj的值为多少。如果computeOomAdjLocked 执行完了,这个进程的adj 还是UNKNOWN_ADJ,此时会在updateOomAdjLocked 方法中将adj 设置为ProcessList.CACHED_APP_MIN_ADJ到ProcessList.CACHED_APP_MAX_ADJ之间的某一个值。详情参见上一篇文章。
第三部分
//第三部分处理包含Activity的进程时// //依次轮询进程中的Activity,app的adj会由if (!foregroundActivities && activitiesSize > 0) {for (int j = 0; j < activitiesSize; j++) {final ActivityRecord r = app.activities.get(j);if (r.app != app) {continue;}//如果进程包含可见Activity,即该进程是个可见进程,if (r.visible) {//更新状态,原因是在for循环里面可能先走了后面的分支,然后再进入了本分支//这样最终进程的adj就由最重要的activity的状态决定了。if (adj > ProcessList.VISIBLE_APP_ADJ) {//adj大于VISIBLE_APP_ADJ时,才更新对应的adj//之前提到的正在处理广播、服务或测试的进程(也就是第一部分),adj为FOREGROUND,是小于VISIBLE_APP_ADJ//因此不会在此更新,adj = ProcessList.VISIBLE_APP_ADJ;app.adjType = "visible";}if (procState > ActivityManager.PROCESS_STATE_TOP) {procState = ActivityManager.PROCESS_STATE_TOP;}//正在处理广播、服务或测试的进程,如果它们的调度策略为BACKGROUND//但又包含了可见Activity时,调度策略变更为DEFAULTschedGroup = Process.THREAD_GROUP_DEFAULT;app.cached = false;app.empty = false;foregroundActivities = true;//注意break了//发现可见Activity时,直接可以结束循环break;} else if (r.state == ActivityState.PAUSING || r.state == ActivityState.PAUSED) {//如果进程包含处于PAUSING或PAUSED状态的Activity时//将其oom_adj调整为“用户可察觉”的的等级,这个等级还是很高的if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {adj = ProcessList.PERCEPTIBLE_APP_ADJ;app.adjType = "pausing";}if (procState > ActivityManager.PROCESS_STATE_TOP) {procState = ActivityManager.PROCESS_STATE_TOP;}schedGroup = Process.THREAD_GROUP_DEFAULT;app.cached = false;app.empty = false;foregroundActivities = true;//注意并不会break} else if (r.state == ActivityState.STOPPING) {//包含处于Stopping状态Activity的进程,其oom_adj也被置为PERCEPTIBLE_APP_ADJif (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {adj = ProcessList.PERCEPTIBLE_APP_ADJ;app.adjType = "stopping";}if (!r.finishing) {if (procState > ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {procState = ActivityManager.PROCESS_STATE_LAST_ACTIVITY;}}app.cached = false;app.empty = false;foregroundActivities = true;} else {//只是含有cached-activity的进程,仅调整procStateif (procState > ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) {procState = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;app.adjType = "cch-act";}}}}
这一部分主要是遍历进程当中的所有页面,每一个页面都有一个adj,而最终进程的adj 选取其中最小的值。例如一个进程有一个可见页面有一个正在执行onPause 的页面,那么进程的adj 是ProcessList.VISIBLE_APP_ADJ,再比例进程有一个正在执行onPause的页面以及一个正在执行onStop 的页面,此时进程的adj 是ProcessList.PERCEPTIBLE_APP_ADJ。
如果没有可见页面,也不是正在执行onPause 以及onStop 的页面,就是已经处于后台的将进程,,此时adj 为cacheAdj。 参见第二部的else 分支。
第四部分
//第四部分主要用于处理一些特殊的进程。if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {//进程包含前台服务或被强制在前台运行时//oom_adj被调整为PERCEPTIBLE_APP_ADJ,只是procState略有不同if (app.foregroundServices) {// 当前进程包含前台服务adj = ProcessList.PERCEPTIBLE_APP_ADJ;procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;app.cached = false;app.adjType = "fg-service";schedGroup = Process.THREAD_GROUP_DEFAULT;} else if (app.forcingToForeground != null) {//例如当前进程正在弹出一个Toast。(是否可以使用定时Toast来保活)adj = ProcessList.PERCEPTIBLE_APP_ADJ;procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;app.cached = false;app.adjType = "force-fg";app.adjSource = app.forcingToForeground;schedGroup = Process.THREAD_GROUP_DEFAULT;}}///AMS的HeavyWeight进程单独处理if (app == mHeavyWeightProcess) {if (adj > ProcessList.HEAVY_WEIGHT_APP_ADJ) {// We don't want to kill the current heavy-weight process.adj = ProcessList.HEAVY_WEIGHT_APP_ADJ;schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;app.cached = false;app.adjType = "heavy";}if (procState > ActivityManager.PROCESS_STATE_HEAVY_WEIGHT) {procState = ActivityManager.PROCESS_STATE_HEAVY_WEIGHT;}}//home进程特殊处理if (app == mHomeProcess) {if (adj > ProcessList.HOME_APP_ADJ) {adj = ProcessList.HOME_APP_ADJ;schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;app.cached = false;app.adjType = "home";}if (procState > ActivityManager.PROCESS_STATE_HOME) {procState = ActivityManager.PROCESS_STATE_HOME;}}//前台进程之前的一个进程,也就是上次显示的进程if (app == mPreviousProcess && app.activities.size() > 0) {if (adj > ProcessList.PREVIOUS_APP_ADJ) {// This was the previous process that showed UI to the user.// We want to try to keep it around more aggressively, to give// a good experience around switching between two apps.adj = ProcessList.PREVIOUS_APP_ADJ;schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;app.cached = false;app.adjType = "previous";}if (procState > ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {procState = ActivityManager.PROCESS_STATE_LAST_ACTIVITY;}}if (false) Slog.i(TAG, "OOM " + app + ": initial adj=" + adj+ " reason=" + app.adjType);// By default, we use the computed adjustment. It may be changed if// there are applications dependent on our services or providers, but// this gives us a baseline and makes sure we don't get into an// infinite recursion.app.adjSeq = mAdjSeq;app.curRawAdj = adj;app.hasStartedServices = false;//处理正在进行backup工作的进程if (mBackupTarget != null && app == mBackupTarget.app) {// If possible we want to avoid killing apps while they're being backed upif (adj > ProcessList.BACKUP_APP_ADJ) {if (DEBUG_BACKUP) Slog.v(TAG, "oom BACKUP_APP_ADJ for " + app);adj = ProcessList.BACKUP_APP_ADJ;if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND) {procState = ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND;}app.adjType = "backup";app.cached = false;}if (procState > ActivityManager.PROCESS_STATE_BACKUP) {procState = ActivityManager.PROCESS_STATE_BACKUP;}}
这里以及前面三个部分在处理adj的时候都会先判断一下adj的大小,例如本部分的第一行
adj > ProcessList.PERCEPTIBLE_APP_ADJ。这里这句代码的主要作用是过滤掉前面已经设置了adj的进程。
因为computeOomAdjLocked 里面设置adj 是按照由小到大的顺序处理的,因此在前面部分被设置了某个非UNKNOWN_ADJ的值一般后续比较adj大于某个值的条件都不在处理。
这一部分主要处理了一些特殊的进程,如执行前台Service 的进程,桌面进程,前一次显示的进程等等。
第五部分
boolean mayBeTop = false;for (int is = app.services.size()-1;is >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ|| schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE|| procState > ActivityManager.PROCESS_STATE_TOP);is--) {ServiceRecord s = app.services.valueAt(is);//通过startService启动过Serviceif (s.startRequested) {app.hasStartedServices = true;if (procState > ActivityManager.PROCESS_STATE_SERVICE) {procState = ActivityManager.PROCESS_STATE_SERVICE;}//app之前启动过Activityif (app.hasShownUi && app != mHomeProcess) {if (adj > ProcessList.SERVICE_ADJ) {app.adjType = "cch-started-ui-services";}} else {//MAX_SERVICE_INACTIVITY为activity启动service后,系统最多保留Service的时间。//没有启动过Activity,并且30分钟之内活跃过的服务进程if (now < (s.lastActivity + ActiveServices.MAX_SERVICE_INACTIVITY)) {if (adj > ProcessList.SERVICE_ADJ) {//虽然处于后台,相当于提高了adj的级别,//app.hasShownUi && app != mHomeProcess 这个分支内部内有提高adj级别//说明一个纯粹的服务进程的优先级是高于既有ui又有服务的进程的adj = ProcessList.SERVICE_ADJ;app.adjType = "started-services";app.cached = false;}}//处理Service存在超时的情况,可见超时时也不会调整oom_adjif (adj > ProcessList.SERVICE_ADJ) {app.adjType = "cch-started-services";}}}//bindService 启动的Service。for (int conni = s.connections.size()-1;conni >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ|| schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE|| procState > ActivityManager.PROCESS_STATE_TOP);conni--) {ArrayList<ConnectionRecord> clist = s.connections.valueAt(conni);//多次调用bind多次调用bindService 绑定同一个Service,每次绑定的//参数可能不一样。for (int i = 0;i < clist.size() && (adj > ProcessList.FOREGROUND_APP_ADJ|| schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE|| procState > ActivityManager.PROCESS_STATE_TOP);i++) {// XXX should compute this based on the max of// all connected clients.ConnectionRecord cr = clist.get(i);if (cr.binding.client == app) {// Binding to ourself is not interesting.continue;}//bingService时添加了BIND_WAIVE_PRIORITY这个flag。if ((cr.flags& Context.BIND_WAIVE_PRIORITY) == 0) {// client 是调用bindService 的进程,也就是客户端。ProcessRecord client = cr.binding.client;//计算出客户端进程的oom_adj//由此可看出Android oom_adj的计算多么麻烦int clientAdj = computeOomAdjLocked(client, cachedAdj,TOP_APP, doingAll, now);int clientProcState = client.curProcState;if (clientProcState >= ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) {// If the other app is cached for any reason, for purposes here// we are going to consider it empty. The specific cached state// doesn't propagate except under certain conditions.clientProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;}String adjType = null;//BIND_ALLOW_OOM_MANAGEMENT置为1时,先按照通常的处理方式,调整服务端进程的adjTypeif ((cr.flags&Context.BIND_ALLOW_OOM_MANAGEMENT) != 0) {if (app.hasShownUi && app != mHomeProcess) {if (adj > clientAdj) {adjType = "cch-bound-ui-services";}app.cached = false;//当前进程展示过ui, 会将clientAdj修改为当前进程的adj,clientAdj = adj;clientProcState = procState;} else {if (now >= (s.lastActivity+ ActiveServices.MAX_SERVICE_INACTIVITY)) {if (adj > clientAdj) {adjType = "cch-bound-services";}//服务已经好长时间没有执行过了,那么同样 会将clientAdj修改为当前进程的adjclientAdj = adj;}//若是距离服务上次活跃时间还没有超过30min,那么adj 放到后面修改}}//当前进程优先级低于客户端//adj>clientAdj 表明client此时可能是正在显示或是可见的页面,而当前进程是后台进程if (adj > clientAdj) {if (app.hasShownUi && app != mHomeProcess&& clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {adjType = "cch-bound-ui-services";} else {//这里主要是处理client 的adj 大于当前进程adj的情形。//例如进程A 绑定了另一个进程B 内的一个Service。//此时可能A进程为当前正在显示的进程而B 是一个后台进程。//此时可以适当提高一个进程B的adj。//例如B本来是CACHED_APP_MAX_ADJ但由于A 是可见进程,//此时B 的adj 也会是可见进程。//bindService 同时添加了BIND_ABOVE_CLIENT与BIND_IMPORTANTif ((cr.flags&(Context.BIND_ABOVE_CLIENT|Context.BIND_IMPORTANT)) != 0) {//adj 最小取值是PERSISTENT_SERVICE_ADJ。adj = clientAdj >= ProcessList.PERSISTENT_SERVICE_ADJ? clientAdj : ProcessList.PERSISTENT_SERVICE_ADJ;} else if ((cr.flags&Context.BIND_NOT_VISIBLE) != 0&& clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ&& adj > ProcessList.PERCEPTIBLE_APP_ADJ) {//BIND_NOT_VISIBLE表示不将服务端当作visible进程看待adj = ProcessList.PERCEPTIBLE_APP_ADJ;} else if (clientAdj > ProcessList.VISIBLE_APP_ADJ) {//例如客户端是PERCEPTIBLE_APP_ADJ,这里一般也是提升//adj 的级别adj = clientAdj;} else {if (adj > ProcessList.VISIBLE_APP_ADJ) {adj = ProcessList.VISIBLE_APP_ADJ;}}if (!client.cached) {app.cached = false;}adjType = "service";}}// adj <=clientAdj,例如客户端是后台进程,当前进程为正在显示的进程。//if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {//BIND_NOT_FOREGROUND表示系统将阻止驻留该服务的进程具有前台优先级if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {schedGroup = Process.THREAD_GROUP_DEFAULT;}if (clientProcState <= ActivityManager.PROCESS_STATE_TOP) {if (clientProcState == ActivityManager.PROCESS_STATE_TOP) {// Special handling of clients who are in the top state.// We *may* want to consider this process to be in the// top state as well, but only if there is not another// reason for it to be running. Being on the top is a// special state, meaning you are specifically running// for the current top app. If the process is already// running in the background for some other reason, it// is more important to continue considering it to be// in the background state.mayBeTop = true;//降低clientProcStateclientProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;} else {// Special handling for above-top states (persistent// processes). These should not bring the current process// into the top state, since they are not on top. Instead// give them the best state after that.//也是降低clientProcStateclientProcState =ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;}}} else {if (clientProcState <ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND) {clientProcState =ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND;}}if (procState > clientProcState) {procState = clientProcState;}if (procState < ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND&& (cr.flags&Context.BIND_SHOWING_UI) != 0) {app.pendingUiClean = true;}if (adjType != null) {app.adjType = adjType;app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_SERVICE_IN_USE;app.adjSource = cr.binding.client;app.adjSourceProcState = clientProcState;app.adjTarget = s.name;}}//看成是activityif ((cr.flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {app.treatLikeActivity = true;}// 根据当前进程activity来调整adj和schedGroupfinal ActivityRecord a = cr.activity;//a 非空表示Service 是从页面a 启动。//&Context.BIND_ADJUST_WITH_ACTIVITY是指当从Activity绑定到该进程时,// 允许目标服务进程根据该activity的可见性来提升优先级if ((cr.flags&Context.BIND_ADJUST_WITH_ACTIVITY) != 0) {if (a != null && adj > ProcessList.FOREGROUND_APP_ADJ &&(a.visible || a.state == ActivityState.RESUMED|| a.state == ActivityState.PAUSING)) {//提高服务进程的优先级adj = ProcessList.FOREGROUND_APP_ADJ;if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {schedGroup = Process.THREAD_GROUP_DEFAULT;}app.cached = false;app.adjType = "service";app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_SERVICE_IN_USE;app.adjSource = a;app.adjSourceProcState = procState;app.adjTarget = s.name;}}}}}
这里主要是处理进程内运行了Service的情况,根据Service的启动情形有分为两种情况。
通过startService启动:
这里Service 所在进程没有启动父ui 并且服务在30分钟活跃过,那么adj 为ProcessList.SERVICE_ADJ,其余的情形的adj 依然是在前面设置的PROCESS_STATE_CACHED_ACTIVITY。换句话说一个Service 在一定时间不在运行之后就会无效。
通过bindService 启动:
这里主要是根据bindService 提供的Flag 来适当的提高Service 进程的adj,使得服务进程的内存没有那么容易被回收。具体Flag 的意义大家可以查询相关资料。
假设一个进程既有activity 又有Service 那么该进程的adj 取何值?
该Service 是starService 且没有被bindService绑定过,同时进程内没有ContentProvider。
由上图可以看到当一个服务进程展示过ui的情况下会修改adjType,但是没有给adj 赋值,此时adj 依然是前面设置的UNKNOW_ADJ。
updateOomAdjLocked
updateOomAdjLocked 通过computeOomAdjLocked 修改进程的adj 之后会判断进程的adj是否大于等于UNKNOWN_ADJ, 一个有ui的Service 进程的adj 是UNKNOWN_ADJ,正好满足条件
之后进程app 的adj 会被设置为CACHED_APP_MIN_ADJ到CACHED_APP_MAX_ADJ 之间的某一个值。
一般启动了服务的进程往往是希望服务在后台能够执行某些任务,这样看是不希望这些服务因为进程被杀而过早的被终止的。正确的做法是,对于期望较长时间留在后台的服务,应该将服务运行在单独的进程里,即是UI进程与Servie进程分离,这样期望长时间留在后台的Serivce会获得较小的Adj值,而占有大量内存的UI进程则会分类为Cached(后台)进程,能够在需要的时候更快地被回收。
第六部分
省略,这一部分主要是根据ContentProivder 来设置adj,逻辑类似Service。
第七部分
//第七部分if (mayBeTop && procState > ActivityManager.PROCESS_STATE_TOP) {// A client of one of our services or providers is in the top state. We// *may* want to be in the top state, but not if we are already running in// the background for some other reason. For the decision here, we are going// to pick out a few specific states that we want to remain in when a client// is top (states that tend to be longer-term) and otherwise allow it to go// to the top state.switch (procState) {case ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND:case ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND:case ActivityManager.PROCESS_STATE_SERVICE:// These all are longer-term states, so pull them up to the top// of the background states, but not all the way to the top state.procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;break;default:// Otherwise, top is a better choice, so take it.procState = ActivityManager.PROCESS_STATE_TOP;break;}}//if (procState >= ActivityManager.PROCESS_STATE_CACHED_EMPTY) {if (app.hasClientActivities) {// This is a cached process, but with client activities. Mark it so.procState = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT;app.adjType = "cch-client-act";} else if (app.treatLikeActivity) {// This is a cached process, but somebody wants us to treat it like it has// an activity, okay!// 将Service 看成是activity .procState = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;app.adjType = "cch-as-act";}}// 对Service进程做一些特殊处理if (adj == ProcessList.SERVICE_ADJ) {if (doingAll) {//每次updateOomAdj时,将mNewNumAServiceProcs置为0//然后LRU list中,从后往前数,前1/3的service进程就是AService//其余的就是bService//mNumServiceProcs为上一次update时,service进程的数量//mNewNumAServiceProcs 表示当前处理的第几个Serviceapp.serviceb = mNewNumAServiceProcs > (mNumServiceProcs/3);mNewNumServiceProcs++;//Slog.i(TAG, "ADJ " + app + " serviceb=" + app.serviceb);if (!app.serviceb) {// 如果不是bService,但内存回收等级过高,也被视为bServiceif (mLastMemoryLevel > ProcessStats.ADJ_MEM_FACTOR_NORMAL&& app.lastPss >= mProcessList.getCachedRestoreThresholdKb()) {app.serviceHighRam = true;app.serviceb = true;//Slog.i(TAG, "ADJ " + app + " high ram!");} else {mNewNumAServiceProcs++;//Slog.i(TAG, "ADJ " + app + " not high ram!");}} else {app.serviceHighRam = false;}}if (app.serviceb) {//LRU中后1/3的Service,都是AServiceadj = ProcessList.SERVICE_B_ADJ;}}//计算完毕app.curRawAdj = adj;//if基本没有用,maxAdj已经是最大的UNKNOW_ADJif (adj > app.maxAdj) {adj = app.maxAdj;if (app.maxAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) {schedGroup = Process.THREAD_GROUP_DEFAULT;}}//最后做一些记录和调整app.curAdj = app.modifyRawOomAdj(adj);app.curSchedGroup = schedGroup;app.curProcState = procState;app.foregroundActivities = foregroundActivities;return app.curRawAdj;
这一部分主要是根据前面计算修改一些进程的proState以及根据服务在进程列表的位置修改adj。
所有的进程保存在一个列表里面,从后往前数,前1/3的service进程就是AService
总结
这篇关于android 内存管理之adj 《三》的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!