ART运行时Foreground GC和Background GC切换过程分析.docx

上传人:b****7 文档编号:11156938 上传时间:2023-02-25 格式:DOCX 页数:28 大小:47.94KB
下载 相关 举报
ART运行时Foreground GC和Background GC切换过程分析.docx_第1页
第1页 / 共28页
ART运行时Foreground GC和Background GC切换过程分析.docx_第2页
第2页 / 共28页
ART运行时Foreground GC和Background GC切换过程分析.docx_第3页
第3页 / 共28页
ART运行时Foreground GC和Background GC切换过程分析.docx_第4页
第4页 / 共28页
ART运行时Foreground GC和Background GC切换过程分析.docx_第5页
第5页 / 共28页
点击查看更多>>
下载资源
资源描述

ART运行时Foreground GC和Background GC切换过程分析.docx

《ART运行时Foreground GC和Background GC切换过程分析.docx》由会员分享,可在线阅读,更多相关《ART运行时Foreground GC和Background GC切换过程分析.docx(28页珍藏版)》请在冰豆网上搜索。

ART运行时Foreground GC和Background GC切换过程分析.docx

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,ListpendingResults,

ListpendingNewIntents,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,因为它涉及到进程状态的更新,它的实现如下所示:

[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

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 经管营销 > 经济市场

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1