ART运行时Foreground GC和Background GC切换过程分析.docx
- 文档编号:11156938
- 上传时间:2023-02-25
- 格式:DOCX
- 页数:28
- 大小:47.94KB
ART运行时Foreground GC和Background GC切换过程分析.docx
《ART运行时Foreground GC和Background GC切换过程分析.docx》由会员分享,可在线阅读,更多相关《ART运行时Foreground GC和Background GC切换过程分析.docx(28页珍藏版)》请在冰豆网上搜索。
ART运行时ForegroundGC和BackgroundGC切换过程分析
ART运行时ForegroundGC和BackgroundGC切换过程分析
通过前面一系列文章的学习,我们知道了ART运行时既支持Mark-SweepGC,又支持CompactingGC。
其中,Mark-SweepGC执行效率更高,但是存在内存碎片问题;而CompactingGC执行效率较低,但是不存在内存碎片问题。
ART运行时通过引入ForegroundGC和BackgroundGC的概念来对这两种GC进行扬长避短。
本文就详细分析它们的执行过程以及切换过程。
在前面和这两篇文章中,我们都有提到了ART运行时的ForegroundGC和BackgroundGC。
它们是在ART运行时启动通过-Xgc和-XX:
BackgroundGC指定的。
但是在某同一段时间,ART运行时只会执行ForegroundGC或者BackgroundGC。
也就是说,ForegroundGC和BackgroundGC在整个应用程序的生命周期中是交替执行的。
这就涉及到从ForegroundGC切换到BackgroundGC,或者从BackgroundGC切换到ForegroundGC的问题。
现在两个问题就来了:
什么时候执行ForegroundGC,什么时候执行BackgroundGC?
什么GC作为ForegroundGC最合适,什么GC作为BackgroundGC最合适?
顾名思义,Foreground指的就是应用程序在前台运行时,而Background就是应用程序在后台运行时。
因此,ForegroundGC就是应用程序在前台运行时执行的GC,而Background就是应用程序在后台运行时执行的GC。
应用程序在前台运行时,响应性是最重要的,因此也要求执行的GC是高效的。
相反,应用程序在后台运行时,响应性不是最重要的,这时候就适合用来解决堆的内存碎片问题。
因此,Mark-SweepGC适合作为ForegroundGC,而CompactingGC适合作为BackgroundGC。
但是,ART运行时又是怎么知道应用程序目前是运行在前台还是后台呢?
这就需要负责管理应用程序组件的系统服务ActivityManagerService闪亮登场了。
因为ActivityManagerService清楚地知道应用程序的每一个组件的运行状态,也就是它们当前是在前台运行还是后台运行,从而得到应用程序是前台运行还是后台运行的结论。
我们通过图1来描述应用程序的运行状态与ForegroundGC和BackgroundGC的时序关系,如下所示:
从图1还可以看到,当从ForegroundGC切换到BackgroundGC,或者从BackgroundGC切换到ForegroundGC,会发生一次CompactingGC的行为。
这是由于ForegroundGC和BackgroundGC的底层堆空间结构是一样的,因此发生ForegroundGC和BackgroundGC切换时,需要将当前存活的对象从一个Space转移到另外一个Space上去。
这个刚好就是Semi-SpaceGC和GenerationalSemi-SpaceGC合适干的事情。
图1中的显示了应用程序的两个状态:
kProcessStateJankPerceptible和kProcessStateJankImperceptible。
其中,kProcessStateJankPerceptible说的就是应用程序处于用户可感知的状态,这就相当于是前台状态;而kProcessStateJankImperceptible说的就是应用程序处于用户不可感知的状态,这就相当于是后台状态。
接下来,我们就结合ActivityManagerService来分析ForegroundGC和BackgroundGC的切换过程。
从前面这个系列的文章可以知道,应用程序组件是通过ActivityManagerService进行启动的。
例如,当我们从Launcher启动一个应用程序时,实际的是在这个应用程序中Action和Category分别被配置为MAIN和LAUNCHER的Activity。
这个Activity最终由ActivityManagerService通知其所在的进程进行启动工作的,也就是通过ApplicationThread类的成员函数scheduleLaunchActivity开始执行启动工作的。
其它类型的组件的启动过程也是类似的,这里我们仅以Activity的启动过程作为示例,来说明ART运行时如何知道要进行ForegroundGC和BackgroundGC切换的。
ApplicationThread类的成员函数scheduleLaunchActivity的实现如下所示:
[java]viewplaincopy
publicfinalclassActivityThread{
......
privateclassApplicationThreadextendsApplicationThreadNative{
......
publicfinalvoidscheduleLaunchActivity(Intentintent,IBindertoken,intident,
ActivityInfoinfo,ConfigurationcurConfig,CompatibilityInfocompatInfo,
IVoiceInteractorvoiceInteractor,intprocState,Bundlestate,
PersistableBundlepersistentState,List
List
ProfilerInfoprofilerInfo){
updateProcessState(procState,false);
ActivityClientRecordr=newActivityClientRecord();
r.token=token;
r.ident=ident;
r.intent=intent;
r.voiceInteractor=voiceInteractor;
r.activityInfo=info;
patInfo=compatInfo;
r.state=state;
r.persistentState=persistentState;
r.pendingResults=pendingResults;
r.pendingIntents=pendingNewIntents;
r.startsNotResumed=notResumed;
r.isForward=isForward;
r.profilerInfo=profilerInfo;
updatePendingConfiguration(curConfig);
sendMessage(H.LAUNCH_ACTIVITY,r);
}
......
}
......
}
这个函数定义在文件frameworks/base/core/java/android/app/ActivityThread.java中。
ApplicationThread类的成员函数scheduleLaunchActivity首先是调用另外一个成员函数updateProcessState更新进程的当前状态,接着再将其余参数封装在一个ActivityClientRecord对象中,并且将这个ActivityClientRecord对象通过一个H.LAUNCH_ACTIVITY消息传递给应用程序主线程处理。
应用程序主线程处理对这个消息的处理就是启动指定的Activity,这个过程可以参考前面这个系列的文章。
ApplicationThread类的成员函数scheduleLaunchActivity还调用了另外一个成员函数updatePendingConfiguration将参数curConfig描述的系统当前配置信息保存下来待后面处理。
我们主要关注ApplicationThread类的成员函数updateProcessState,因为它涉及到进程状态的更新,它的实现如下所示:
[java]viewplaincopy
publicfinalclassActivityThread{
......
privateclassApplicationThreadextendsApplicationThreadNative{
......
publicvoidupdateProcessState(intprocessState,booleanfromIpc){
synchronized(this){
if(mLastProcessState!
=processState){
mLastProcessState=processState;
//UpdateDalvikstatebasedonActivityManager.PROCESS_STATE_*constants.
finalintDALVIK_PROCESS_STATE_JANK_PERCEPTIBLE=0;
finalintDALVIK_PROCESS_STATE_JANK_IMPERCEPTIBLE=1;
intdalvikProcessState=DALVIK_PROCESS_STATE_JANK_IMPERCEPTIBLE;
//TODO:
Tunethissincethingslikegmailsyncareimportantbackgroundbutnotjankperceptible.
if(processState<=ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND){
dalvikProcessState=DALVIK_PROCESS_STATE_JANK_PERCEPTIBLE;
}
VMRuntime.getRuntime().updateProcessState(dalvikProcessState);
......
}
}
}
......
}
......
}
这个函数定义在文件frameworks/base/core/java/android/app/ActivityThread.java中。
ApplicationThread类的成员变量mLastProcessState描述的是进程上一次的状态,而参数processState描述的是进程当前的状态。
当这两者的值不一致时,就表明进程的状态发生了变化,这时候就需要调用VMRuntime类的成员函数updateProcessState通知ART运行时,以便ART运行时可以在ForegroundGC和BackgroundGC之间切换。
ActivityManagerService一共定义了14种进程状态,如下所示:
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
publicclassActivityManager{
......
/**@hideProcessisapersistentsystemprocess.*/
publicstaticfinalintPROCESS_STATE_PERSISTENT=0;
/**@hideProcessisapersistentsystemprocessandisdoingUI.*/
publicstaticfinalintPROCESS_STATE_PERSISTENT_UI=1;
/**@hideProcessishostingthecurrenttopactivities.Notethatthiscovers
*allactivitiesthatarevisibletotheuser.*/
publicstaticfinalintPROCESS_STATE_TOP=2;
/**@hideProcessisimportanttotheuser,andsomethingtheyareawareof.*/
publicstaticfinalintPROCESS_STATE_IMPORTANT_FOREGROUND=3;
/**@hideProcessisimportanttotheuser,butnotsomethingtheyareawareof.*/
publicstaticfinalintPROCESS_STATE_IMPORTANT_BACKGROUND=4;
/**@hideProcessisinthebackgroundrunningabackup/restoreoperation.*/
publicstaticfinalintPROCESS_STATE_BACKUP=5;
/**@hideProcessisinthebackground,butitcan'trestoreitsstatesowewant
*totrytoavoidkillingit.*/
publicstaticfinalintPROCESS_STATE_HEAVY_WEIGHT=6;
/**@hideProcessisinthebackgroundrunningaservice.Unlikeoom_adj,thislevel
*isusedforboththenormalrunninginbackgroundstateandtheexecuting
*operationsstate.*/
publicstaticfinalintPROCESS_STATE_SERVICE=7;
/**@hideProcessisinthebackgroundrunningareceiver.Notethatfromthe
*perspectiveofoom_adjreceiversrunatahigherforegroundlevel,butforour
*prioritizationherethatisnotnecessaryandputtingthembelowservicesmeans
*manyfewerchangesinsomeprocessstatesastheyreceivebroadcasts.*/
publicstaticfinalintPROCESS_STATE_RECEIVER=8;
/**@hideProcessisinthebackgroundbuthoststhehomeactivity.*/
publicstaticfinalintPROCESS_STATE_HOME=9;
/**@hideProcessisinthebackgroundbuthoststhelastshownactivity.*/
publicstaticfinalintPROCESS_STATE_LAST_ACTIVITY=10;
/**@hideProcessisbeingcachedforlateruseandcontainsactivities.*/
publicstaticfinalintPROCESS_STATE_CACHED_ACTIVITY=11;
/**@hideProcessisbeingcachedforlateruseandisaclientofanothercached
*processthatcontainsactivities.*/
publicstaticfinalintPROCESS_STATE_CACHED_ACTIVITY_CLIENT=12;
/**@hideProcessisbeingcachedforlateruseandisempty.*/
publicstaticfinalintPROCESS_STATE_CACHED_EMPTY=13;
......
}
这些进程状态值定义在文件frameworks/base/core/java/android/app/ActivityManager.java。
每一个进程状态都通过一个整数来描述,其中,值越小就表示进程越重要。
ART运行时将状态值大于等于PROCESS_STATE_IMPORTANT_FOREGROUND的进程都认为是用户可感知的,也就是前台进程,其余的进程则认为是用户不可感知的,也就是后台进程。
通过这种方式,ApplicationThread类的成员函数updateProcessState就可以简化ART运行时对进程状态的处理。
除了上述的Activity的Launch启动生命周期函数被ActivityManagerService通知调用时,Activity的Resume生命周期函数被ActivityManagerService通知调用调用时,也会发生类似的通过VMRuntime类的成员函数updateProcessState通知ART运行时应用程序状态发生了改变。
对于其它的组件,例如BroadcastReceiver组件被触发时,Service组件被创建以及被绑定时,也会通过VMRuntime类的成员函数updateProcessState通知ART运行时应用程序状态发生了改变。
不过,上述组件的生命周期对应的都是应用程序处于前台时的情况,也就是要求ART运行时从BackgroundGC切换为ForegroundGC的情况。
当应用程序处于后台时,ActivityManagerService是通过直接设置应用程序的状态来通知ART运行时应用程序状态发生了改变的。
ApplicationThread类实现了一个Binder接口setProcessState,供ActivityManagerService直接设置应用程序的状态,它的实现如下所示:
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
publicfinalclassActivityThread{
......
privateclassApplicationThreadextendsApplicationThreadNative{
......
publicvoidsetProcessState(intstate){
updateProcessState(state,true);
}
......
}
......
}
这个函数定义在文件frameworks/base/core/java/android/app/ActivityThread.java中。
ApplicationThread类实现的Binder接口setProcessState也是通过上面分析的成员函数updateProcessState来通知ART运行时进程状态发生了改变的。
不过这时候进程的状态就有可能是从前面进程变为后台进程,例如当运行在该进程的Activity组件处理Stop状态时。
接下来我们继续分析VMRuntime类的成员函数updateProcessState的实现,以便了解ART运行时执行ForegroundGC和BackgroundGC切换的过程,如下所示:
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
publicfinalclassVMRuntime{
......
/**
*Lettheheapknowofthenewprocessstate.Thiscanchangeallocationandgarbagecollection
*behaviorregardingtrimmingandcompaction.
*/
publicnativevoidupdateProcessState(intstate);
......
}
这个函数定义在文件libcore/libart/src/main/java/dalvik/system/VMRuntime.java中。
VMRuntime类的成员函数updateProcessState是一个Native函数,它由C++层的函数VMRuntime_updateProcessState实现,如下所示:
[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片
staticvoidVMRuntime_updateProcessState(JNIEnv*env,jobject,jintprocess_state){
Runtime:
:
Current()->GetHeap()->UpdateProcessState(static_cast : ProcessState>(process_state)); ...... } 这个函数定义在文件art/runtime/native/dalvik_system_VMRuntime.cc中。 函数VMRuntime_updateProcessState主要是调用了Heap类的成员函数UpdateProcessState来通知ART运行时切换ForegroundGC和BackgroundGC,后者的实现如下所示: [cpp]viewplaincopy在CODE上查看代码片派生到我的代码片 voidHeap: : Upd
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- ART运行时Foreground GC和Background GC切换过程分析 ART 运行 Foreground GC Background 切换 过程 分析