
art运行时mark-compact( mc)gc执行过程分析.doc
22页ART 运行时 Mark-Compact( MC)GC 执行过程分析除了 Semi-Space(SS)GC 和 Generational Semi-Space(GSS)GC,ART 运行时还引入了第三种 Compacting GC:Mark-Compact(MC)GC这三种 GC 虽然都是 Compacting GC,不过它们的实现方式却有很大不同SS GC 和 GSS GC 需两个 Space 来压缩内存,而 MC GC 只需一个 Space 来压缩内存本文就详细分析 MC GC 的执行过程从前面一文可以知道,Mark-Compact GC 主要是针对 ART 运行时正在使用的 Bump Pointer Space 进行压缩,如图 1 所示:从图 1 可以看出,当 Mark-Compact GC 执行完成之后,原来位于 Bump Pointer Space 上的仍然存活的对象会被依次移动至原 Bump Pointer Space 的左侧,并且按地址从小到大紧凑地排列在一起这个过程不需要借助于额外的 Space 来完成这一点是 Mark-Compact GC与 Semi-Space GC、Generational Semi-Space GC 的显著区别。
不过,Mark-Compact GC 与 Semi-Space GC、Generational Semi-Space GC 一样,除了需要对 ART 运行时当前使用的 Bump Pointer Space 进行内在压缩之外,还需要修改其它Space 对 Bump Pointer Space 的引用,因为 Bump Pointer Space 的对象发生了移动此外,ART 运行时堆的 Non Moving Space 和 Large Object Space 也会进行像 Mark-Sweep GC 一样的垃圾回收从前面一文还可以知道,在 ART 运行时内部,所有的 GC 都是通过 Heap 类的成员函数 CollectGarbageInternal 开始执行的,并且当决定要执行 Mark-Compact GC 时,最终会以 MarkCompact 类的成员函数 RunPhases 作为入口点,如下所示:[cpp] view plain copyvoid MarkCompact::RunPhases() { Thread* self = Thread::Current(); InitializePhase(); CHECK(!Locks::mutator_lock_->IsExclusiveHeld(self)); { ScopedPause pause(this); ...... MarkingPhase(); ReclaimPhase(); } ...... FinishPhase(); } 这个函数定义在文件 art/runtime/gc/collector/mark_compact.cc 中。
与 Semi-Space GC、Generational Semi-Space GC 一样,Mark-Compact GC 的执行过程也分为初始化、标记、回收和结束四个阶段,对应的函数分别为 MarkCompact 类的成员函数 InitializePhase、MarkingPhase、ReclaimPhase 和 FinishPhase其中,标记和回收阶段是在挂起其它的 ART 运行时线程的前提下进行的注意,挂起其它的 ART 运行时线程的操作通过 ScopedPause 类的构造函数实现的当标记和回收阶段结束, ScopedPause 类的析构函数就会自动恢复之前被挂起的 ART 运行时线程接下来,我们就分别分析 Mark-Compact GC 的四个阶段的执行过程,即MarkCompact 类的成员函数 InitializePhase、MarkingPhase、ReclaimPhase 和 FinishPhase 的实现Mark-Compact GC 的初始化阶段由 MarkCompact 类的成员函数 InitializePhase 实现,如下所示:[cpp] view plain copyvoid MarkCompact::InitializePhase() { TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings()); mark_stack_ = heap_->GetMarkStack(); ...... immune_region_.Reset(); ...... // TODO: I don't think we should need heap bitmap lock to Get the mark bitmap. ReaderMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_); mark_bitmap_ = heap_->GetMarkBitmap(); live_objects_in_space_ = 0; } 这个函数定义在文件 art/runtime/gc/collector/mark_compact.cc 中。
MarkCompact 类的成员函数 InitializePhase 主要就是执行一些初始化工作,例如获得 ART 运行时堆的 Mark Stack、Mark Bitmap,保存在成员变量 mark_stack_和mark_bitmap_中,并且重置 MarkCompact 类的成员变量 immune_region_描述的一个不进行垃圾回收的 Space 区间为空,以及将成员变量 live_objects_in_space_的值置为0MarkCompact 类的成员变量 live_objects_in_space_用来描述 Mark-Compact GC 执先完成后,Bump Pointer Space 还有多少对象是存活的 Mark-Compact GC 的标记阶段来 MarkCompact 类的成员函数 MarkingPhase 实现,如下所示:[cpp] view plain copyvoid MarkCompact::MarkingPhase() { TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings()); Thread* self = Thread::Current(); // Bitmap which describes which objects we have to move. objects_before_forwarding_.reset(accounting::ContinuousSpaceBitmap::Create( "objects before forwarding", space_->Begin(), space_->Size())); // Bitmap which describes which lock words we need to restore. objects_with_lockword_.reset(accounting::ContinuousSpaceBitmap::Create( "objects with lock words", space_->Begin(), space_->Size())); CHECK(Locks::mutator_lock_->IsExclusiveHeld(self)); // Assume the cleared space is already empty. BindBitmaps(); t.NewTiming("ProcessCards"); // Process dirty cards and add dirty cards to mod-union tables. heap_->ProcessCards(GetTimings(), false); // Clear the whole card table since we can not Get any additional dirty cards during the // paused GC. This saves memory but only works for pause the world collectors. t.NewTiming("ClearCardTable"); heap_->GetCardTable()->ClearCardTable(); // Need to do this before the checkpoint since we don't want any threads to add references to // the live stack during the recursive mark. if (kUseThreadLocalAllocationStack) { t.NewTiming("RevokeAllThreadLocalAllocationStacks"); heap_->RevokeAllThreadLocalAllocationStacks(self); } t.NewTiming("SwapStacks"); heap_->SwapStacks(self); { WriterMutexLock mu(self, *Locks::heap_bitmap_lock_); MarkRoots(); // Mark roots of immune spaces. UpdateAndMarkModUnion(); // Recursively mark remaining objects. MarkReachableObjects(); } ProcessReferences(self); { ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_); SweepSystemWeaks(); } // Revoke buffers before measuring how many objects were moved since the TLABs need to be revoked // before they are properly counted. RevokeAllThreadLocalBuffers(); ...... } 这个函数定义在文件 art/runtime/gc/collector/mark_compact.cc 中。
MarkCompact 类的成员函数 MarkingPhase 的执行过程如下所示:1. 针对当前要进行 Mark-Compact 的 Bump Pointer Space,创建两个ContinuousSpaceBitmap,分别保存在 MarkCompact 类的成员变量objects_before_forwarding_和 objects_with_lockword_其中,前者用来记录当前要进行Mark-Compact 的 Bump Pointer Space 的存活对象,而后者用来记录上述的存活对象在移动前它们的 LockWord 有没有被覆盖如果被覆盖了,那么在它们移动之后,需要恢复它们之前的 LockWord后面我们就可以看到,Mark-Compact GC 在移动对象的时候,会先计算出每一个需要移动的对象的新地址,并且将该新地址作为一个 Forwarding Address 记录它的 LockWord 中因此,当对象移动到新地址后,。
