art垃圾回收(1)

333 阅读3分钟

void GarbageCollector::Run() {  
  ThreadList* thread_list = Runtime::Current()->GetThreadList();  
  uint64_t start_time = NanoTime();  
  pause_times_.clear();  
  duration_ns_ = 0;  
  
  InitializePhase();  
  
  if (!IsConcurrent()) {  
    // Pause is the entire length of the GC.  
    uint64_t pause_start = NanoTime();  
    ATRACE_BEGIN("Application threads suspended");  
    thread_list->SuspendAll();  
    MarkingPhase();  
    ReclaimPhase();  
    thread_list->ResumeAll();  
    ATRACE_END();  
    uint64_t pause_end = NanoTime();  
    pause_times_.push_back(pause_end - pause_start);  
  } else {  
    Thread* self = Thread::Current();  
    {  
      ReaderMutexLock mu(self, *Locks::mutator_lock_);  
      MarkingPhase();  
    }  
    bool done = false;  
    while (!done) {  
      uint64_t pause_start = NanoTime();  
      ATRACE_BEGIN("Suspending mutator threads");  
      thread_list->SuspendAll();  
      ATRACE_END();  
      ATRACE_BEGIN("All mutator threads suspended");  
      done = HandleDirtyObjectsPhase();  
      ATRACE_END();  
      uint64_t pause_end = NanoTime();  
      ATRACE_BEGIN("Resuming mutator threads");  
      thread_list->ResumeAll();  
      ATRACE_END();  
      pause_times_.push_back(pause_end - pause_start);  
    }  
    {  
      ReaderMutexLock mu(self, *Locks::mutator_lock_);  
      ReclaimPhase();  
    }  
  }  
  
  uint64_t end_time = NanoTime();  
  duration_ns_ = end_time - start_time;  
  
  FinishPhase();  
}  

这个函数定义在文件art/runtime/gc/collector/garbage_collector.cc中。
GarbageCollector类的成员函数Run的实现就对应于图1所示的左边和右边的两个流程。
图1所示的左边流程是用来执行非并行GC的,过程如下所示:

  1. 调用子类实现的成员函数InitializePhase执行GC初始化阶段。
  2. 挂起所有的ART运行时线程。
  3. 调用子类实现的成员函数MarkingPhase执行GC标记阶段。
  4. 调用子类实现的成员函数ReclaimPhase执行GC回收阶段。
  5. 恢复第2步挂起的ART运行时线程。
  6. 调用子类实现的成员函数FinishPhase执行GC结束阶段。

图1所示的右边流程是用来执行并行GC的,过程如下所示:

  1. 调用子类实现的成员函数InitializePhase执行GC初始化阶段。
  2. 获取用于访问Java堆的锁。
  3. 调用子类实现的成员函数MarkingPhase执行GC并行标记阶段。
  4. 释放用于访问Java堆的锁。
  5. 挂起所有的ART运行时线程。
  6. 调用子类实现的成员函数HandleDirtyObjectsPhase处理在GC并行标记阶段被修改的对象。。
  7. 恢复第4步挂起的ART运行时线程。
  8. 重复第5到第7步,直到所有在GC并行阶段被修改的对象都处理完成。
  9. 获取用于访问Java堆的锁。
  10. 调用子类实现的成员函数ReclaimPhase执行GC回收阶段。
  11. 释放用于访问Java堆的锁。
  12. 调用子类实现的成员函数FinishPhase执行GC结束阶段。

从上面的分析就可以看出,并行GC和非并行GC的区别在于:

  1. 非并行GC的标记阶段和回收阶段是在挂住所有的ART运行时线程的前提下进行的,因此,只需要执行一次标记即可。
  2. 并行GC的标记阶段只锁住了Java堆,因此它不能阻止那些不是正在分配对象的ART运行时线程同时运行,而这些同进运行的ART运行时线程可能会引用了一些在之前的标记阶段没有被标记的对象。如果不对这些对象进行重新标记的话,那么就会导致它们被GC回收,造成错误。因此,与非并行GC相比,并行GC多了一个处理脏对象的阶段。所谓的脏对象就是我们前面说的在GC标记阶段同时运行的ART运行时线程访问或者修改过的对象。
  3. 并行GC并不是自始至终都是并行的,例如,处理脏对象的阶段就是需要挂起除GC线程以外的其它ART运行时线程,这样才可以保证标记阶段可以结束。