您好,欢迎访问三七文档
当前位置:首页 > 行业资料 > 其它行业文档 > ART运行时垃圾收集(GC)过程分析
ART运行时垃圾收集(GC)过程分析ART运行时与Dalvik虚拟机一样,都使用了Mark-Sweep算法进行垃圾回收,因此它们的垃圾回收流程在总体上是一致的。但是ART运行时对堆的划分更加细致,因而在此基础上实现了更多样的回收策略。不同的策略有不同的回收力度,力度越大的回收策略,每次回收的内存就越多,并且它们都有各自的使用情景。这样就可以使得每次执行GC时,可以最大限度地减少应用程序停顿。本文就详细分析ART运行时的垃圾收集过程。ART运行时的垃圾收集收集过程如图1所示:图1的最上面三个箭头描述触发GC的三种情况,左边的流程图描述非并行GC的执行过程,右边的流程图描述并行GC的执行流程,接下来我们就详细图中涉及到的所有细节。在前面一文中,我们提到了两种可能会触发GC的情况。第一种情况是没有足够内存分配请求的分存时,会调用Heap类的成员函数CollectGarbageInternal触发一个原因为kGcCauseForAlloc的GC。第二种情况下分配出请求的内存之后,堆剩下的内存超过一定的阀值,就会调用Heap类的成员函数RequestConcurrentGC请求执行一个并行GC。Heap类的成员函数RequestConcurrentGC的实现如下所示:[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片voidHeap::RequestConcurrentGC(Thread*self){//MakesurethatwecandoaconcurrentGC.Runtime*runtime=Runtime::Current();DCHECK(concurrent_gc_);if(runtime==NULL||!runtime-IsFinishedStarting()||!runtime-IsConcurrentGcEnabled()){return;}{MutexLockmu(self,*Locks::runtime_shutdown_lock_);if(runtime-IsShuttingDown()){return;}}if(self-IsHandlingStackOverflow()){return;}//Wealreadyhavearequestpending,noreasontostartmoreuntilweupdate//concurrent_start_bytes_.concurrent_start_bytes_=std::numeric_limitssize_t::max();JNIEnv*env=self-GetJniEnv();DCHECK(WellKnownClasses::java_lang_Daemons!=NULL);DCHECK(WellKnownClasses::java_lang_Daemons_requestGC!=NULL);env-CallStaticVoidMethod(WellKnownClasses::java_lang_Daemons,WellKnownClasses::java_lang_Daemons_requestGC);CHECK(!env-ExceptionCheck());}这个函数定义在文件art/runtime/gc/heap.cc。只有满足以下四个条件,Heap类的成员函数RequestConcurrentGC才会触发一个并行GC:1.ART运行时已经启动完毕。2.ART运行时支持并行GC。ART运行时默认是支持并行GC的,但是可以通过启动选项-Xgc来关闭。3.ART运行时不是正在关闭。4.当前线程没有发生栈溢出。上述4个条件都满足之后,Heap类的成员函数RequestConcurrentGC就将成员变量concurrent_start_bytes_的值设置为类型size_t的最大值,表示目前正有一个并行GC在等待执行,以阻止触发另外一个并行GC。最后,Heap类的成员函数RequestConcurrentGC调用Java层的java.lang.Daemons类的静态成员函数requestGC请求执行一次并行GC。Java层的java.lang.Daemons类在加载的时候,会启动五个与堆或者GC相关的守护线程,如下所示:[java]viewplaincopy在CODE上查看代码片派生到我的代码片publicfinalclassDaemons{......publicstaticvoidstart(){ReferenceQueueDaemon.INSTANCE.start();FinalizerDaemon.INSTANCE.start();FinalizerWatchdogDaemon.INSTANCE.start();HeapTrimmerDaemon.INSTANCE.start();GCDaemon.INSTANCE.start();}......}这个类定义在文件libcore/libart/src/main/java/java/lang/Daemons.java中。这五个守护线程分别是:1.ReferenceQueueDaemon:引用队列守护线程。我们知道,在创建引用对象的时候,可以关联一个队列。当被引用对象引用的对象被GC回收的时候,被引用对象就会被加入到其创建时关联的队列去。这个加入队列的操作就是由ReferenceQueueDaemon守护线程来完成的。这样应用程序就可以知道那些被引用对象引用的对象已经被回收了。2.FinalizerDaemon:析构守护线程。对于重写了成员函数finalize的对象,它们被GC决定回收时,并没有马上被回收,而是被放入到一个队列中,等待FinalizerDaemon守护线程去调用它们的成员函数finalize,然后再被回收。3.FinalizerWatchdogDaemon:析构监护守护线程。用来监控FinalizerDaemon线程的执行。一旦检测那些重定了成员函数finalize的对象在执行成员函数finalize时超出一定的时候,那么就会退出VM。4.HeapTrimmerDaemon:堆裁剪守护线程。用来执行裁剪堆的操作,也就是用来将那些空闲的堆内存归还给系统。5.GCDaemon:并行GC线程。用来执行并行GC。Java层的java.lang.Daemons类的静态成员函数requestGC被调用时,就会唤醒上述的并行GC线程,然后这个并行GC线程就会通过JNI调用Heap类的成员函数ConcurrentGC,它的实现如下所示:[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片voidHeap::ConcurrentGC(Thread*self){{MutexLockmu(self,*Locks::runtime_shutdown_lock_);if(Runtime::Current()-IsShuttingDown()){return;}}//WaitforanyGCscurrentlyrunningtofinish.if(WaitForConcurrentGcToComplete(self)==collector::kGcTypeNone){CollectGarbageInternal(next_gc_type_,kGcCauseBackground,false);}}这个函数定义在文件art/runtime/gc/heap.cc中。只要ART运行时当前不是处于正在关闭的状态,那么Heap类的成员函数ConcurrentGC就会检查当前是否正在执行GC。如果是的话,那么就等待它执行完成,然后再调用Heap类的成员函数CollectGarbageInternal触发一个原因为kGcCauseBackground的GC。否则的话,就直接调用Heap类的成员函数CollectGarbageInternal触发一个原因为kGcCauseBackground的GC。从这里就可以看到,无论是触发GC的原因是kGcCauseForAlloc,还是kGcCauseBackground,最终都是通过调用Heap类的成员函数CollectGarbageInternal来执行GC的。此外,还有第三种情况会触发GC,如下所示:[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片voidHeap::CollectGarbage(boolclear_soft_references){//EvenifwewaitedforaGCwestillneedtodoanotherGCsinceweaksallocatedduringthe//lastGCwillnothavenecessarilybeencleared.Thread*self=Thread::Current();WaitForConcurrentGcToComplete(self);CollectGarbageInternal(collector::kGcTypeFull,kGcCauseExplicit,clear_soft_references);}这个函数定义在文件art/runtime/gc/heap.cc。当我们调用Java层的java.lang.System的静态成员函数gc时,如果ART运行时支持显式GC,那么就它就会通过JNI调用Heap类的成员函数CollectGarbageInternal来触发一个原因为kGcCauseExplicit的GC。ART运行时默认是支持显式GC的,但是可以通过启动选项-XX:+DisableExplicitGC来关闭。从上面的分析就可以看出,ART运行时在三种情况下会触发GC,这三种情况通过三个枚举kGcCauseForAlloc、kGcCauseBackground和kGcCauseExplicitk来描述。这三人枚举的定义如下所示:[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片//WhatcausedtheGC?enumGcCause{//GCtriggeredbyafailedallocation.ThreaddoingallocationisblockedwaitingforGCbefore//retryingallocation.kGcCauseForAlloc,//AbackgroundGCtryingtoensurethereisfreememoryaheadofallocations.kGcCauseBackground,//AnexplicitSystem.gc()call.kGcCauseExplicit,};这三个枚举定义在文件art/runtime/gc/heap.h中。从上面的分析还可以看出,ART运行时的所有GC都是以Heap类的成员函数CollectGarbageInternal为入口,它的实现如下所示:[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片collector::GcTypeHeap::CollectGarbageInternal(collector::GcTypegc_type,GcCausegc_cause,boolclear_soft_references){Thread*self=Thread::Current();......//EnsurethereisonlyoneGCatatime.boolstart_collect=false;while(!start_collect){{MutexLockmu(self,*gc_complete_lock_);if(!is_gc_running_){is_gc_running_=true;start_collect=true;}}if(!start_collect){//TODO:timinglogthis.WaitForConcurrentGcToCompl
本文标题:ART运行时垃圾收集(GC)过程分析
链接地址:https://www.777doc.com/doc-23768 .html