ART运行时Foreground GC和Background GC切换过程分析Word格式文档下载.docx
《ART运行时Foreground GC和Background GC切换过程分析Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《ART运行时Foreground GC和Background GC切换过程分析Word格式文档下载.docx(28页珍藏版)》请在冰点文库上搜索。
因此,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<
ResultInfo>
pendingResults,
List<
Intent>
pendingNewIntents,booleannotResumed,booleanisForward,
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,因为它涉及到进程状态的更新,它的实现如下所示:
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);
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直接设置应用程序的状态,它的实现如下所示:
publicvoidsetProcessState(intstate){
updateProcessState(state,true);
ApplicationThread类实现的Binder接口setProcessState也是通过上面分析的成员函数updateProcessState来通知ART运行时进程状态发生了改变的。
不过这时候进程的状态就有可能是从前面进程变为后台进程,例如当运行在该进程的Activity组件处理Stop状态时。
接下来我们继续分析VMRuntime类的成员函数updateProcessState的实现,以便了解ART运行时执行ForegroundGC和BackgroundGC切换的过程,如下所示:
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<
gc:
ProcessState>
(process_state));
这个函数定义在文件art/runtime/native/dalvik_system_VMRuntime.cc中。
函数VMRuntime_updateProcessState主要是调用了Heap类的成员函数UpdateProcessState来通知ART运行时切换ForegroundGC和BackgroundGC,后者的实现如下所示:
voidHeap:
Upd