前言
进程优先级实际上是系统对进程重要性的一个客观评价。根据这个评价的结果来为进程分配不同的系统资源,这个资源包括内存资源和CPU资源。为了保证“公平公正”的评价每个进程,Google工程师为此设计了一套评价系统。本文试图从面相对象的角度和功能设计者角度来理解该功能,具体思路如下:
要实现一个功能,有必要的时候我们会去为他制定一些属性,对于设计者而言这些属性肯定是必须的,因此作为使用者我们必须理解这些属性的意义是什么。
同样要实现一个功能,设计者会定制一些该功能特有的行为,在代码里面体现为特定的函数,那么我们作为使用者,必须了解以下几个面:a.该行为的能产生什么样的结果,即行为的目的,b.该行为的触发条件,即什么时候会用到这些方法,为什么在这个时候要去触发?
本文会从如下三个关键词和三个关键方法来展开分析和讨论
- adj:通过调整oom_score_adj来影响进程寿命(Lowmemorykiller杀进程策略);
- schedGroup:影响进程的CPU资源调度与分配;
- procState:从进程所包含的四大组件运行状态来评估进程状态,影响framework的内存控制策略。比如控制缓存进程和空进程个数上限依赖于procState,再比如控制APP执行handleLowMemory()的触发时机等
- updateOomAdjLocked:更新
- computeOomAdjLocked:计算
- applyOomAdjLocked:应用
ADJ
AMS中有几个和adj相关的非常重要的方法:
- updateOomAdjLocked(ProcessRecord app, int cachedAdj,
ProcessRecord TOP_APP, boolean doingAll, long now)
- updateOomAdjLocked(ProcessRecord app, boolean oomAdjAll)
- updateOomAdjLocked()
- computeOomAdjLocked(ProcessRecord app, int cachedAdj, ProcessRecord TOP_APP,
boolean doingAll, long now)
- applyOomAdjLocked(ProcessRecord app, boolean doingAll, long now,
long nowElapsed)
这个几个方法的关系如下:updateOomAdjLocked(更新),包括computeOomAdjLocked(计算)和applyOomAdjLocked(应用),这俩个动作!
总体算法示意图
updateOomAdjLocked触发场景
该方法作为adj更新的核心方法,设计者用它来更新进程的adj。我们在前言说过进程优先级的评价是“公平公正”的,但是“公平公正”并不等同于平均,平均分配系统资源实际上是不符合用户体验的需求的。用户必定希望自己想用的进程能够得到足够的系统资源。没有使用的进程尽可能的分配较少的资源。因此,设计者必须了解当前的进程所处的场景。然后,基于不同场景来及时的更新adj,及时的重新分配系统资源。因此,设计必须在Android系统中进行“埋点”。
下面是搜索的updateOomAdjLocked,该方法的埋点结果。涉及的类
updateOomAdjLocked大致可以分为俩类:1.带参数的(在后面把它称为updateOomAdjLockedA:针对指定的单个进程更新优先级,如果oomAdjAll这个参数为true,就有可能去调用updateOomAdjLockedB),2.带参数的(在后面把他成为updateOomAdjLockedB对所有进程更新优先级)。
1.ActiveServices
- bindServiceLocked:最开始是由于AMS中的binderervices被调用,即该场景可以理解为当有服务绑定的时候,就会有updateOomAdjLockedB,当然由于绑定服务只单个应用的行为,那么updateOomAdjLockeB也是针对单个应用的。之所有绑定服务的时候,需要调用updateOomAdjLockedB,是因为,服务进程的adj是由,client和server端之间的关系来决定的。
- unbindServiceLocked: 最开始是由于AMS中的unbindService被调用,即该场景可以理解为当有服务解绑的时候,就会有updateOomAdjLockedB。这个原因和第一点是一样的,服务的解绑也会导致client端和server之间的关系发生变化。
- unbindServiceLocked:这里还进行了updateOomAdjLockedA
- realStartServiceLocked:这个最开始是由于AMS中startServices或者attachApplicationLocked被调用。即该场景可以理解为:有startServices或者新的进程起来,会去updateOomAdjLockedA.这原因可以理解为:一个服务或者进程起来,它会导致系统其它进程的状态发生变化,(比如一个进程的前后台关系),因此要调用就会有updateOomAdjLockedA,
- sendServiceArgsLocked:
即服务起来或者进程别杀的时候。这个函数是一个私有函数,被调用的地方如下:
第三个参数为:adj值是否已经调整过,调整或就不在进行更新,
即有三处调用:
bringUpServiceLocked:即服务起来的时候。
realStartServiceLocked :第三个参数为false,因此,不用更新。第二不用更新的原因是,第二方法最终是在realStartServiceLocked被调用的,在该方法调用之前,前面已经调用过updateOomAdjLockedA。
cleanUpRemovedTaskLocked:进程被杀死的时候调用
- bringDownServiceLocked:服务解绑的场景相关,服务解绑
- bringDownServiceLocked:服务解绑的场景相关,服务destroy
- removeConnectionLocked:最开始是由于服务被解绑或者服务被杀死。调用updateOomAdjLockedB
- serviceDoneExecutingLocked
BroadcastQueue