ART运行时垃圾收集(GC)过程分析.docx
ART运行时垃圾收集(GC)过程分析ART运行晡与Da1.vik虚拟机一样,都使用了Hark-Sreep算法进行坨圾回收,因此它们的垃圾回收流程在总体上是一段的.但是ART运行时对堆的划分更加细致,因而在此基础上实现了更多样的回收策略。不同的策略有不同的回收力度.力度越大的回收策略,标次回收的内存就越多,并且它们都有各自的使用情景.这样就可以使得每次执行GC时,可以最大限度地减少应用程序停顿.本文就详细分析ART运行时的垃圾收集过程.ART运行时的垃圾也集收集过程如图1所示:图1ART运徊的GC执行就图1的股上面三个箭头描述触发GC的三种情况,左边的滋程图描述非并行GC的执行过程,右边的流程图描述并行GC的执行流程,接下来我们就详细图中涉及到的所有细节.在前面一文中,我们提到了两种可能会触发GC的情况.笫一种情况是没有足够内存分配请求的分存时,会调用HeiiP类的成员函数Co1.ICC1.GarbaKCInIernaI触发一个原因为kGcCaus<ForA1.Ioc的GC。第二种情况卜分配出请求的内存之后,惟料下的内存超过一定的阀值,就会调用I1.e叩类的成员函数RcquestConcurrentGC请求执行一个并行GC.Heap类的成员函数Reiiucs1.Concurren1.GC的实现如下所示:cppviewp1.aincopy在CODE上查看代码片派生到我的代码片voidHeap:RequestConcurrentGC(Threadtse1.f)(/Makesurethat<ecandoaconcurrentGC.Runii三e*runtime=Runtime:CurrentO;DCHECK(concurrentcj;if(runtimeN1.1.1.!runtime->IsFinishedStarting()!runtime->ISConcurrentGcEnab1.ed()return;)(Mutex1.ockmu(seif.*1.,ocks:runtimo_shutdown_1.ock_);if(runtime->IsShuttingDounO)(return:if<se1f->1s1.1.andIingStackverf1owO)(return;)/Wea1.readyhavearequestpending,noreasontostartmoreunti1.weux1.ate/COnCUrrcn1._s1.ar1._by1.c$_concurrent_start_bytes_-std:nuneric_1.imits<size_t>:;JNIEnv*env=Se1.f-XJetJniEnvO:DCHECK(Ie1.IKnownC1.asscs:java_1.anR_Daeiiioris!=NU1.1.);DCHECK(Ie1.IKnownC1.asses:java_1.ang_Dacmons_requestGC!-N1.1.D:env-X;a1.IStaticVoidMethod(We1.IKnownC1.asses:java1.angj)aemons,We1.IKriownC1.asses:java_1.ang_DaeiDons_requestGC);CHECK(!env->ExcetionChcck0):)这个函数定义在文件art/runti11>pgcheap.CCe只有满足以下四个条件,HeaP类的成其函数RCQUeSICOnCUITen1.GC才会触发,个并行GG1.ART运行时已经启动完毕.2 .ART运行时支持并行GGART运行时默认是支持并行GC的,但是可以通过启动选项-XgC来关闭。3 .ART运行时不是正在关闭.I.当前我程没有发生栈溢出。上述4个条件都满足之后,Heap类的成员函数RequestConcurrentGC就将成员变盘concurrentstart_bytes的值设SIt为类型size_t的最大值,表示目前正有,个并行GC在等传执行,以阻止触发另外一个并行GC最后Hap类的成员函数RequestConcurrentGC调用JaVa层的java.1.ang.Dneaons类的静态成员函数requestC请求执行次并行(;CJaVa层的java.1.ang.Daomcns类在加教的时帔,会端动五个与堆或者(;C相关的守护线程如下所示:javaviewp1.aincopy在CODE上查石代码片派生到我的代码片pub1.icfina1.c1.assDae三ons(pub1.icstaticvoidstartO(RefcrericeQueucDaefDon.INSTANCE,startO;Fina1.izerDaemon.INSTANCE,start():Einf1.1.iZerWatchdogDaemon.INSTANCE,start():HeapTrimmerDaeBon.INSTANCE,startO:GCDiicmon.INSTANCE,startO;这个类定义在文件IibCore1.ibartsrcunjaajava1.angDaanons.java中。这五个守护线程分别是:1. RcfrerceQueueDac<non:引用队列守护线程。我们知道,在创立引用对象的时候,可以关联一个队列.当被引用对象引用的对象被Ge回收的时候.被引用对象就会被参加到其创立时关联的队列去.这个参加队列的操作就是由ReferenCeQUeUeOaCinon守护跳程来完成的.这样应用程序就可以知道那些被引用对象引用的对我己羟被回收了。2. Fina1.izerDaewn:析构守护线程.对于写了成员函数fina1.ize的对象.它们被GC决定回收时,并没有马上阳可收,而是被放入到一个队列中,等待FinaIiZerI)acmon守妒线程去网用它们的成员函数fina1.ize,然后再被回收。3. Fina1.iZerWatchdogDaenion:析构监护守护线程“用来监控Finn1.iZerDaemon线程的执行.一旦检测那些曳定了成员函数fina1.ize的对象在执行成员函数fina1.ize时超出一定的时候.那么就会退出VM.4. HcapTrinunerDaso”:堆祓剪守护线程.用来执行裁剪地的操作,也就是用来将那些空闲的堆内存归还给系统.5. GCDaeff1.on;并行GC设程。用来执行并行GCJava层的java.1.ang.Daemons类的静态成员函数FequestGC被调用时,就会唤醒匕述的并行GC线程.然后这个并行GC蜿程就会通过JN1.调用HeaP类的成员函数ConCUrrentGC,它的实现如下所示:cppviewp1.aincopy在CODE上查看代码片源生到我的代码片voidHeap:ConcurrentGC(Thread*se1.f)Mutex1.ockmu(se1.f,*1.ocks:runtime_shutdown_1.ock_);if(Runtime:Current)->IsShutti11DwnO)(return:/ffaitforanyGCscurrent1.yrunningtofinish.if(Wai1.ForConcurrertGcToCom1.e1.e(sc1.f)=co1.1.ector:ikGcTypeNone)(Co1.1.ectGarbageInternaI(next_gc_type_,kGcCauseBackground.fa1.se);)这个函数定义在文件art/runtiegchca.cc中。只要ART运行时当前不是处于正在关闭的状态.版么呢叩类的成员函数COnCUrnMGe就会检查当前足否正在执行GC.如果是的话,那么就等待它执行完成,然后再两用HeaP类的成员函数COI1.OCtGarbago1.ntOrna1.触发个原因为kGcCauseBackground的GC,否则的话,就11接调用Heap类的成员函数Ce1.1.cc1.GarbaKeIn1.crna1.触发一个原因为kGcCauscBackrund的GC从这里就可以看到,无论是触发GC的股因是kCcmse1.rAUoc,还足k(;CCaU“Hnckgmund,最终都是通过调用HeaD类的成员函数Co1.1.CCIGarbagC1.n1.ema1.来执行Ge的。此外,还有第三种情况会触发GG如下所示:cppviewp1.aincopy在CWE上查看代码片派生到我的代码片voidHeap:JCo1.1.ectGarbage(boo1.c1.ear_sofpreferences)(/EvenifwcwaitedforaGCwesti1.1.needtodoanotherGCsincewcaksa1.1.ocatedduringthe/1.astGCwi1.1.nothavenecessariIybeenc1.eared.Thread*se1.f=Thread:Current();WaitForConcurrentGcToComp1.ete(se1.f);Co1.1.ectGarbageIntcrrui1.(co1.1.ector:kGcTypcFu1.I1RGcCauseExp1.icit,c1ear_softReferences):)这个函数定义在文件art/runtiae/gc/heap.cc.当我们调用Java层的ja、a1.ang.System的峥态成员函数gc时,如果ART运行时支持显式GG那么就它就会通过JN1.调用HCaP类的成员函数CO1.ICC1.GdrbaXCIn1.ergI1.来触发一个原因为kGcCauscEXP1.iCi1.的GC,ART运行时默认是支持显式GC的.但是可以通过启动选项XX:*DiSdbIdp1.icitGC来关闭.从上面的分析就可以看出,ART运行时在三种情况下会触发GC.这三种情况通过三个枚举kGcCauscForAI1.oCxkGcCiiuscBckround和kGcCauscExp1.ici1.k来描述。这三人枚举的定义如下所示:cppviewp1.aincopy在CwE上查看代码片派生到我的代码片/IhatcausedtheGC?enuaGcCause/GCtriggeredbyafai1.eda1.1.ocation.Threaddoinga1.1.ocationisb1.ockedWUi1.ingforGCbefore/retryinga1.1.ocation.RGcCauseForA1.1.oc,/AbackgroundGCtryingtoensurethereisfreeBceoiyaheadofa1.1.ocations.kGcCauseBackground,/nexp1.icitSystea.gc()ca1.1.RGcCauseExp1.icit,);这三个枚举定义在文件art/runtime/gc/heap.h中从上面的分析还可以看出,RRT运行时的所有GC都是以Heap类的成员函数Co1.1.ectGarbageInterna1.为入口.它的实现如下所示:cpviewp1.aincopy在CoDE上杳看代码片源生到我的代码片co1.1.ector:GcTypeHeap:Co1.IectGarbageIntcrna1.(co1.1.ector:GcTypect