ART运行时垃圾收集(GC)过程分析

本文详细分析了ART运行时的垃圾收集过程,包括触发GC的条件、执行流程和不同类型的GC。讨论了Heap类的角色,以及如何通过RequestConcurrentGC和ConcurrentGC触发并行GC。同时,提到了显式GC的触发方式和GcCause枚举的三种类型。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow

也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

               

  ART运行时与Dalvik虚拟机一样,都使用了Mark-Sweep算法进行垃圾回收,因此它们的垃圾回收流程在总体上是一致的。但是ART运行时对堆的划分更加细致,因而在此基础上实现了更多样的回收策略。不同的策略有不同的回收力度,力度越大的回收策略,每次回收的内存就越多,并且它们都有各自的使用情景。这样就可以使得每次执行GC时,可以最大限度地减少应用程序停顿。本文就详细分析ART运行时的垃圾收集过程。

老罗的新浪微博:http://weibo.com/shengyangluo,欢迎关注!

        ART运行时的垃圾收集收集过程如图1所示:

图1 ART运行时的GC执行流程

        图1的最上面三个箭头描述触发GC的三种情况,左边的流程图描述非并行GC的执行过程,右边的流程图描述并行GC的执行流程,接下来我们就详细图中涉及到的所有细节。

        在前面ART运行时为新创建对象分配内存的过程分析一文中,我们提到了两种可能会触发GC的情况。第一种情况是没有足够内存分配请求的分存时,会调用Heap类的成员函数CollectGarbageInternal触发一个原因为kGcCauseForAlloc的GC。第二种情况下分配出请求的内存之后,堆剩下的内存超过一定的阀值,就会调用Heap类的成员函数RequestConcurrentGC请求执行一个并行GC。

        Heap类的成员函数RequestConcurrentGC的实现如下所示:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void Heap::RequestConcurrentGC(Thread* self) {  
  2.   // Make sure that we can do a concurrent GC.  
  3.   Runtime* runtime = Runtime::Current();  
  4.   DCHECK(concurrent_gc_);  
  5.   if (runtime == NULL || !runtime->IsFinishedStarting() ||  
  6.       !runtime->IsConcurrentGcEnabled()) {  
  7.     return;  
  8.   }  
  9.   {  
  10.     MutexLock mu(self, *Locks::runtime_shutdown_lock_);  
  11.     if (runtime->IsShuttingDown()) {  
  12.       return;  
  13.     }  
  14.   }  
  15.   if (self->IsHandlingStackOverflow()) {  
  16.     return;  
  17.   }  
  18.   
  19.   // We already have a request pending, no reason to start more until we update  
  20.   // concurrent_start_bytes_.  
  21.   concurrent_start_bytes_ = std::numeric_limits<size_t>::max();  
  22.   
  23.   JNIEnv* env = self->GetJniEnv();  
  24.   DCHECK(WellKnownClasses::java_lang_Daemons != NULL);  
  25.   DCHECK(WellKnownClasses::java_lang_Daemons_requestGC != NULL);  
  26.   env->CallStaticVoidMethod(WellKnownClasses::java_lang_Daemons,  
  27.                             WellKnownClasses::java_lang_Daemons_requestGC);  
  28.   CHECK(!env->ExceptionCheck());  
  29. }  
       这个函数定义在文件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]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public final class Daemons {  
  2.     ......  
  3.   
  4.     public static void start() {  
  5.         ReferenceQueueDaemon.INSTANCE.start();  
  6.         FinalizerDaemon.INSTANCE.start();  
  7.         FinalizerWatchdogDaemon.INSTANCE.start();  
  8.         HeapTrimmerDaemon.INSTANCE.start();  
  9.         GCDaemon.INSTANCE.start();  
  10.     }  
  11.   
  12.     ......  
  13. }  
       这个类定义在文件libcore/libart/src/main/java/java/lang/Daemons.java中。

       这五个守护线程分别是:

       1. ReferenceQueueDaemon:引用队列守护线程。我们知道,在创建引用对象的时候,可以关联一个队列。当被引用对象引用的对象被GC回收的时候,被引用对象就会被加入到其创建时关联的队列去。这个加入队列的操作就是由ReferenceQueueDaemon守护线程来完成的。这样应用程序就可以知道那些被引用对象引用的对象已经被回收了。

       2. FinalizerDaemon:析构守护线程。对于重写了成员函数finalize的对象,它们被GC决定回收时,并没有马上被回收,而是被放入到一个队列中,等待FinalizerDaemon守护线程去调用它们的成员函数finalize,然后再被回收。<

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值