android进程生命周期和ADJ

本文详细介绍了Android进程的生命周期,分为前台、可见、服务、后台和空进程五个级别,以及各级别的特点。此外,还讲解了Android内存管理中的ADJ(Activity Manager OOM Adj)级别和Lowmemorykiller如何根据阈值进行内存回收。文章还探讨了ADJ算法的更新时机和调整进程状态的三大方法:updateOomAdjLocked、computeOomAdjLocked和applyOomAdjLocked。
摘要由CSDN通过智能技术生成

原文地址:https://shimo.im/docs/D42dNHt99Zw5Yvkd/
一、进程生命周期
在回收资源的时候,系统会根据进程的重要性来从低到高的回收,划分为5个级别:
1.前台进程(Foreground process)
2.可见进程(visible process)
3.服务进程(Service process)
4.后台进程(Background process)
5.空进程(Empty process)
重要性依次递减
1.1 Foreground process
用户当前操作所必须的进程。一般不会终止,除非在万不得已的情况下,系统内存极度不足。
·拥有用户正在交互的Activity(已调用onResume())
·拥有某个Service,后者绑定到用户正在交互的Activity
·拥有正在“前台”运行的Service(服务已调用startForeground)
·拥有正执行一个生命周期回调的Service(onCreate()、onStart()或onDestroy())
·拥有正执行其onReceive()方法的BroadcastReceiver
1.2 Visible process
没有任何前台组件、但仍会影响用户在屏幕上可见内容的进程。可见进程被视为是极其重要的进程,为了维护所有前台进程同时运行而必须终止,负责系统不会终止这些进程。
·拥有不在前台、但仍对用户可见的Activity(已调用onPause())
·拥有绑定到可见(或前台)Activity的Service
1.3 Service process
尽管服务进程与用户所见内容没有直接关联,但是它们通常在执行一些用户关心的操作(比如,在后台播放音乐或从网络下载数据)。因此,除非内存不足以维持所有前台进程可见和可见进程同时运行,否则系统会让服务进程保持运行状态。
·正在运行startService()方法启动的服务,且不属于上述两个更好类别进程的进程。
1.4 Background process
后台进程对用户体验没有直接影响,系统可能随时终止它们,以回收内存供前台进程、可见进程或服务进程使用。通常会有很多后台进程在运行,因此它们在保存在LRU列表中,以确保包含用户最近查看的Activity的进程最后一个被终止。如果某个Activity正确实现了生命周期方法,并保存了其当前状态,则终止其进程不会对用户体验产生明显影响,因为当用户导航回该Activity时,Activity会恢复其所有可见状态。
·对用户不可见的Activity的进程(已调用Activity的onStop()方法)
1.5 Empty process
保留这种进程的唯一目的是用作缓存,以缩短下次在启动运行组件所需的启动时间。为使总体系统资源在进程缓存和底层内核缓存之间保持平衡,系统往往会终止这些进程。
·不含任何活动应用组件的进程
二、Lowmemorykiller
Android的内存回收,主要是依靠Lowmemorykiller来完成的。是一种根据阈(yu)值级别触发相应力度的内存回收机制。
1.ADJ级别
定义在ProcessList.java文件,oom_adj划分为16级,从-17到16之间取值。
【负数重要性最高,依次递减;ADJ小于0都是系统进程】
2.进程state级别
定义在ActivityManager.java文件,process_state划分18类,从-1到16之间取值。
【同上,优先级越高,数字越小】
3.Imk策略
Lowmemorykiller根据当前可用内存情况来进行进程释放,总设计了6个级别,即上表中“解释列”加粗的行,即Lowmemorykiller的杀进程的6档,如下:
CACHED_APP_MAX_ADJ
CACHED_APP_MIN_ADJ
BACKUP_APP_ADJ
PERCEPTIBLE_APP_ADJ
VISIBLE_APP_ADJ
FOREGROUND_APP_ADJ
系统内存从很宽裕到不足,Lowmemorykiller也会相应地从CACHED_APP_MAX_ADJ(第1档)开始杀进程,如果内存还不足,那么会杀CACHED_APP_MIN_ADJ(第2档),不断深入,直到满足内存阈值条件。

三、ADJ算法
Android framework层中承载activity/service/contentprovider/broadcastrecevier的进程是如何根据组件运行状态而动态调节进程自身的状态。
进程有两个比较重要的状态值,即adj(定义在ProcessList.java)和procState(定义在ActivityManager.java)。

1.三大护法
调整进程的adj的核心方法:
updateOomAdjLocked:更新Adj,当目标进程为空,或者被杀返回false,否则返回ture。
computeOomAdjLocked:计算Adj,返回计算后RawAdj的值。
applyOomAdjLocked:应用Adj,当需要杀掉目标进程则返回false;否则返回true。

updateOomAdjLocked方法:
无参方法:updateOomAdjLocked()
一参方法:updateOomAdjLocked(ProcessRecord app)
五参方法:updateOomAdjLocked(ProcessRecord app, int cachedAdj,
ProcessRecord TOP_APP, boolean doingAll, long now)
updateOomAdjLocked实现过程中依次会computeOomAdjLocked和applyOomAdjLocked。
2.ADJ的更新时机
先来说说哪些场景下都会触发updateOomAdjLocked来更新进程adj:
Activity
ASS.realStartActivityLocked: 启动Activity
AS.resumeTopActivityInnerLocked: 恢复栈顶Activity
AS.finishCurrentActivityLocked: 结束当前Activity
AS.destroyActivityLocked: 摧毁当前Activity
Service
位于ActiveServices.java
realStartServiceLocked: 启动服务
bindServiceLocked: 绑定服务(只更新当前app)
unbindServiceLocked: 解绑服务 (只更新当前app)
bringDownServiceLocked: 结束服务 (只更新当前app)
sendServiceArgsLocked: 在bringup或则cleanup服务过程调用 (只更新当前app)
broadcast
BQ.processNextBroadcast: 处理下一个广播
BQ.processCurBroadcastLocked: 处理当前广播
BQ.deliverToRegisteredReceiverLocked: 分发已注册的广播 (只更新当前app)
ContentProvider
AMS.removeContentProvider: 移除provider
AMS.publishContentProviders: 发布provider (只更新当前app)
AMS.getContentProviderImpl: 获取provider (只更新当前app)
Process
位于ActivityManagerService.java
setSystemProcess: 创建并设置系统进程
addAppLocked: 创建persistent进程
attachApplicationLocked: 进程创建后attach到system_server的过程;
trimApplications: 清除没有使用app
appDiedLocked: 进程死亡
killAllBackgroundProcesses: 杀死所有后台进程.即(ADJ>9或removed=true的普通进程)
killPackageProcessesLocked: 以包名的形式 杀掉相关进程;

updateOomAdjLocked
重要参数
[-> ProcessList.java]
空进程存活时长: MAX_EMPTY_TIME = 30min
(缓存+空)进程个数上限:MAX_CACHED_APPS = SystemProperties.getInt(“sys.fw.bg_apps_limit”,32) = 32(默认);
空进程个数上限:MAX_EMPTY_APPS = computeEmptyProcessLimit(MAX_CACHED_APPS) = MAX_CACHED_APPS/2 = 16;
trim空进程个数上限:TRIM_EMPTY_APPS = computeTrimEmptyApps() = MAX_EMPTY_APPS/2 = 8;
trim缓存进程个数上限:TRIM_CACHED_APPS = computeTrimCachedApps() = MAX_CACHED_APPS-MAX_EMPTY_APPS)/3 = 5;
TRIM_CRITICAL_THRESHOLD = 3;
[-> AMS.java]
mBServiceAppThreshold = SystemProperties.getInt(“ro.sys.fw.bservice_limit”, 5);
mMinBServiceAgingTime =SystemProperties.getInt(“ro.sys.fw.bservice_age”, 5000);
mProcessLimit = ProcessList.MAX_CACHED_APPS
mProcessLimit = emptyProcessLimit(空进程上限) + cachedProcessLimit(缓存进程上限)
oldTime = now - ProcessList.MAX_EMPTY_TIME;
LRU进程队列长度 = numEmptyProcs(空进程数) + mNumCachedHiddenProcs(cached进程) + mNumNonCachedProcs(非cached进程)
emptyFactor = numEmptyProcs/3, 且大于等于1
cachedFactor = mNumCachedHiddenProcs/3, 且大于等于1
一参方法
final boolean updateOomAdjLocked(ProcessRecord app) {
//获取栈顶的Activity
final ActivityRecord TOP_ACT = resumedAppLocked();
final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
final boolean wasCached = app.cached;

mAdjSeq++;

//确保cachedAdj>=9
final int cachedAdj = app.curRawAdj >= ProcessList.CACHED_APP_MIN_ADJ
? app.curRawAdj : ProcessList.UNKNOWN_ADJ;

//执行五参updateOomAdjLocked【见小节3.3】
boolean success = updateOomAdjLocked(app, cachedAdj, TOP_APP, false,
SystemClock.uptimeMillis());

//当app cached状态改变,或者curRawAdj=16,则执行无参数updateOomAdjLocked【见小节2.3】
if (wasCached != app.cached || app.curRawAdj == ProcessList.UNKNOWN_ADJ) {
updateOomAdjLocked();
}
return success;
}
该方法主要功能:
执行五参updateOomAdjLocked;
当app经过更新adj操作后,其cached状态改变(包括由cached变成非cached,或者非cached变成cached),或者curRawAdj=16,则执行无参updateOomAdjLocked;
五参方法
private final boolean updateOomAdjLocked(ProcessRecord app, int cachedAdj,
ProcessRecord TOP_APP, boolean doingAll, long now) {
if (app.thread == null) {
return false;
}
//【见小节4】
computeOomAdjLocked(app, cachedAdj, TOP_APP, doingAll, now);

//【见小节5】
return applyOomAdjLocked(app, doingAll, now, SystemClock.elapsedRealtime());
}
该方法是private方法,只提供给一参和无参的同名方法调用,系统中并没有其他地方调用。
无参方法(核心)
final void updateOomAdjLocked() {
//获取栈顶的Activity
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();

//重置所有uid记录,把curProcState设置成16(空进程)
for (int i=mActiveUids.size()-1; i>=0; i–) {
final UidRecord uidRec = mActiveUids.valueAt(i);
uidRec.reset();
}

mAdjSeq++;
mNewNumServiceProcs = 0;
mNewNumAServiceProcs = 0;

final int emptyProcessLimit;
final int cachedProcessLimit;
// mProcessLimit默认值等于32,通过开发者选择可设置,或者厂商会自行调整
if (mProcessLimit <= 0) {
emptyProcessLimit = cachedProcessLimit = 0;
} else if (mProcessLimit == 1) {
emptyProcessLimit = 1;
cachedProcessLimit = 0;
} else {
//则emptyProcessLimit = 16, cachedProcessLimit = 16
emptyProcessLimit = ProcessList.computeEmptyProcessLimit(mProcessLimit);
cachedProcessLimit = mProcessLimit - emptyProcessLimit;
}

//经过计算得 numSlots =3
int numSlots = (ProcessList.CACHED_APP_MAX_ADJ

  • ProcessList.CACHED_APP_MIN_ADJ + 1) / 2;
    int numEmptyProcs = N - mNumNonCachedProcs - mNumCachedHiddenProcs;

//确保空进程个数不大于cached进程数
if (numEmptyProcs > cachedProcessLimit) {
numEmptyProcs = cachedProcessLimit;
}
int emptyFactor = numEmptyProcs/numSlots;
if (emptyFactor < 1) emptyFactor = 1;
int cachedFactor = (mNumCachedHiddenProcs > 0 ? mNumCachedHiddenProcs : 1)/numSlots;
if (cachedFactor < 1) cachedFactor = 1;
int stepCached = 0;
int stepEmpty = 0;
int numCached = 0;
int numEmpty = 0;
int numTrimming = 0;

mNumNonCachedProcs = 0;
mNumCachedHiddenProcs = 0;

//更新所有进程状态(基于当前状态)
int curCachedAdj = ProcessList.CACHED_APP_MIN_ADJ;
int nextCachedAdj = curCachedAdj+1;
int curEmptyAdj = ProcessList.CACHED_APP_MIN_ADJ;
int nextEmptyAdj = curEmptyAdj+2;
ProcessRecord selectedAppRecord = null;
long serviceLastActivity = 0;
int numBServices = 0;
for (int i=N-1; i>=0; i–) {
ProcessRecord app = mLruProcesses.get(i);
if (mEnableBServicePropagation && app.serviceb
&& (app.curAdj == ProcessList.SERVICE_B_ADJ)) {
numBServices++;
for (int s = app.services.size() - 1; s >= 0; s–) {
ServiceRecord sr = app.services.valueAt(s);
//上次活跃时间距离现在小于5s,则不会迁移到BService
if (SystemClock.uptimeMillis() - sr.lastActivity
< mMinBServiceAgingTime) {
continue;
}
if (serviceLastActivity == 0) {
serviceLastActivity = sr.lastActivity;
selectedAppRecord = app;
//记录service上次活动时间最长的那个app
} else if (sr.lastActivity < serviceLastActivity) {
serviceLastActivity = sr.lastActivity;
selectedAppRecord = app;
}
}
}

if (!app.killedByAm && app.thread != null) {
app.procStateChanged = false;
//计算app的adj值【见小节4】
computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, TOP_APP, true, now);

//当进程未分配ad

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值