ART运行时MarkCompact MCGC执行过程分析资料.docx
- 文档编号:25077759
- 上传时间:2023-06-04
- 格式:DOCX
- 页数:36
- 大小:49.91KB
ART运行时MarkCompact MCGC执行过程分析资料.docx
《ART运行时MarkCompact MCGC执行过程分析资料.docx》由会员分享,可在线阅读,更多相关《ART运行时MarkCompact MCGC执行过程分析资料.docx(36页珍藏版)》请在冰豆网上搜索。
ART运行时MarkCompactMCGC执行过程分析资料
ART运行时Mark-Compact(MC)GC执行过程分析
除了Semi-Space(SS)GC和GenerationalSemi-Space(GSS)GC,ART运行时还引入了第三种CompactingGC:
Mark-Compact(MC)GC。
这三种GC虽然都是CompactingGC,不过它们的实现方式却有很大不同。
SSGC和GSSGC需两个Space来压缩内存,而MCGC只需一个Space来压缩内存。
本文就详细分析MCGC的执行过程。
从前面一文可以知道,Mark-CompactGC主要是针对ART运行时正在使用的BumpPointerSpace进行压缩,如图1所示:
从图1可以看出,当Mark-CompactGC执行完成之后,原来位于BumpPointerSpace上的仍然存活的对象会被依次移动至原BumpPointerSpace的左侧,并且按地址从小到大紧凑地排列在一起。
这个过程不需要借助于额外的Space来完成。
这一点是Mark-CompactGC与Semi-SpaceGC、GenerationalSemi-SpaceGC的显著区别。
不过,Mark-CompactGC与Semi-SpaceGC、GenerationalSemi-SpaceGC一样,除了需要对ART运行时当前使用的BumpPointerSpace进行内在压缩之外,还需要修改其它Space对BumpPointerSpace的引用,因为BumpPointerSpace的对象发生了移动。
此外,ART运行时堆的NonMovingSpace和LargeObjectSpace也会进行像Mark-SweepGC一样的垃圾回收。
从前面一文还可以知道,在ART运行时内部,所有的GC都是通过Heap类的成员函数CollectGarbageInternal开始执行的,并且当决定要执行Mark-CompactGC时,最终会以MarkCompact类的成员函数RunPhases作为入口点,如下所示:
[cpp]viewplaincopy
voidMarkCompact:
:
RunPhases(){
Thread*self=Thread:
:
Current();
InitializePhase();
CHECK(!
Locks:
:
mutator_lock_->IsExclusiveHeld(self));
{
ScopedPausepause(this);
......
MarkingPhase();
ReclaimPhase();
}
......
FinishPhase();
}
这个函数定义在文件art/runtime/gc/collector/mark_compact.cc中。
与Semi-SpaceGC、GenerationalSemi-SpaceGC一样,Mark-CompactGC的执行过程也分为初始化、标记、回收和结束四个阶段,对应的函数分别为MarkCompact类的成员函数InitializePhase、MarkingPhase、ReclaimPhase和FinishPhase。
其中,标记和回收阶段是在挂起其它的ART运行时线程的前提下进行的。
注意,挂起其它的ART运行时线程的操作通过ScopedPause类的构造函数实现的。
当标记和回收阶段结束,ScopedPause类的析构函数就会自动恢复之前被挂起的ART运行时线程。
接下来,我们就分别分析Mark-CompactGC的四个阶段的执行过程,即MarkCompact类的成员函数InitializePhase、MarkingPhase、ReclaimPhase和FinishPhase的实现。
Mark-CompactGC的初始化阶段由MarkCompact类的成员函数InitializePhase实现,如下所示:
[cpp]viewplaincopy
voidMarkCompact:
:
InitializePhase(){
TimingLogger:
:
ScopedTimingt(__FUNCTION__,GetTimings());
mark_stack_=heap_->GetMarkStack();
......
immune_region_.Reset();
......
//TODO:
Idon'tthinkweshouldneedheapbitmaplocktoGetthemarkbitmap.
ReaderMutexLockmu(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运行时堆的MarkStack、MarkBitmap,保存在成员变量mark_stack_和mark_bitmap_中,并且重置MarkCompact类的成员变量immune_region_描述的一个不进行垃圾回收的Space区间为空,以及将成员变量live_objects_in_space_的值置为0。
MarkCompact类的成员变量live_objects_in_space_用来描述Mark-CompactGC执先完成后,BumpPointerSpace还有多少对象是存活的。
Mark-CompactGC的标记阶段来MarkCompact类的成员函数MarkingPhase实现,如下所示:
[cpp]viewplaincopy
voidMarkCompact:
:
MarkingPhase(){
TimingLogger:
:
ScopedTimingt(__FUNCTION__,GetTimings());
Thread*self=Thread:
:
Current();
//Bitmapwhichdescribeswhichobjectswehavetomove.
objects_before_forwarding_.reset(accounting:
:
ContinuousSpaceBitmap:
:
Create(
"objectsbeforeforwarding",space_->Begin(),space_->Size()));
//Bitmapwhichdescribeswhichlockwordsweneedtorestore.
objects_with_lockword_.reset(accounting:
:
ContinuousSpaceBitmap:
:
Create(
"objectswithlockwords",space_->Begin(),space_->Size()));
CHECK(Locks:
:
mutator_lock_->IsExclusiveHeld(self));
//Assumetheclearedspaceisalreadyempty.
BindBitmaps();
t.NewTiming("ProcessCards");
//Processdirtycardsandadddirtycardstomod-uniontables.
heap_->ProcessCards(GetTimings(),false);
//ClearthewholecardtablesincewecannotGetanyadditionaldirtycardsduringthe
//pausedGC.Thissavesmemorybutonlyworksforpausetheworldcollectors.
t.NewTiming("ClearCardTable");
heap_->GetCardTable()->ClearCardTable();
//Needtodothisbeforethecheckpointsincewedon'twantanythreadstoaddreferencesto
//thelivestackduringtherecursivemark.
if(kUseThreadLocalAllocationStack){
t.NewTiming("RevokeAllThreadLocalAllocationStacks");
heap_->RevokeAllThreadLocalAllocationStacks(self);
}
t.NewTiming("SwapStacks");
heap_->SwapStacks(self);
{
WriterMutexLockmu(self,*Locks:
:
heap_bitmap_lock_);
MarkRoots();
//Markrootsofimmunespaces.
UpdateAndMarkModUnion();
//Recursivelymarkremainingobjects.
MarkReachableObjects();
}
ProcessReferences(self);
{
ReaderMutexLockmu(self,*Locks:
:
heap_bitmap_lock_);
SweepSystemWeaks();
}
//RevokebuffersbeforemeasuringhowmanyobjectsweremovedsincetheTLABsneedtoberevoked
//beforetheyareproperlycounted.
RevokeAllThreadLocalBuffers();
......
}
这个函数定义在文件art/runtime/gc/collector/mark_compact.cc中。
MarkCompact类的成员函数MarkingPhase的执行过程如下所示:
1.针对当前要进行Mark-Compact的BumpPointerSpace,创建两个ContinuousSpaceBitmap,分别保存在MarkCompact类的成员变量objects_before_forwarding_和objects_with_lockword_。
其中,前者用来记录当前要进行Mark-Compact的BumpPointerSpace的存活对象,而后者用来记录上述的存活对象在移动前它们的LockWord有没有被覆盖。
如果被覆盖了,那么在它们移动之后,需要恢复它们之前的LockWord。
后面我们就可以看到,Mark-CompactGC在移动对象的时候,会先计算出每一个需要移动的对象的新地址,并且将该新地址作为一个ForwardingAddress记录它的LockWord中。
因此,当对象移动到新地址后,就需要恢复它们之前的LockWord值。
2.调用MarkCompact类的成员函数BindBitmaps确定哪些Space是不需要进行垃圾回收的。
3.调用Heap类的成员函数ProcessCards处理DirtyCard,即将它们记录在对应的ModUnionTable中,以便后面可以找到上次GC以来,不需要进行垃圾回收的Space对需要垃圾回收的Space的引用情况。
4.调用CardTable类的成员函数ClearCardTable清零DirtyCard。
因为DirtyCard在经过上一步的操作之后,已经记录在了对应的ModUnionTable,因此现在不需要它们了。
5.如果ART运行时堆使用了线程局部AllocationStack,即在常量kUseThreadLocalAllocationStack等于true的情况下,调用Heap类的成员函数RevokeAllThreadLocalAllocationStacks对它们进行回收。
6.调用Heap类的成员函数SwapStacks交换ART运行时堆的AllocationStack和LiveStack。
7.调用MarkCompact类的成员函数MarkRoots标记根集对象。
8.调用MarkCompact类的成员函数UpdateAndMarkModUnion标记DirtyCard引用的对象。
9.调用MarkCompact类的成员函数MarkReachableObjects标记可达对象,即递归标记根集对象和DirtyCard引用的对象可达的对象。
10.调用MarkCompact类的成员函数ProcessReferences处理引用类型的对象,即SoftReference、WeakReference、PhantomReference和FinalizerReference对象。
11.调用MarkCompact类的成员函数SweepSystemWeaks处理那些没有被标记的常量字符串、Monitor对象和在JNI创建的全局弱引用对象等。
12.调用MarkCompact类的成员函数RevokeAllThreadLocalBuffers回收各个ART运行时线程的局部分配缓冲区。
在上述的操作中,我们主要是分析第2、7、8和9操作,即MarkCompact类的成员函数BindBitmaps、MarkRoots、UpdateAndMarkModUnion和MarkReachableObjects的实现、其它的操作可以参考或者一文。
MarkCompact类的成员函数BindBitmaps的实现如下所示:
[cpp]viewplaincopy
voidMarkCompact:
:
BindBitmaps(){
TimingLogger:
:
ScopedTimingt(__FUNCTION__,GetTimings());
WriterMutexLockmu(Thread:
:
Current(),*Locks:
:
heap_bitmap_lock_);
//Markallofthespaceswenevercollectasimmune.
for(constauto&space:
GetHeap()->GetContinuousSpaces()){
if(space->GetGcRetentionPolicy()==space:
:
kGcRetentionPolicyNeverCollect||
space->GetGcRetentionPolicy()==space:
:
kGcRetentionPolicyFullCollect){
CHECK(immune_region_.AddContinuousSpace(space))<<"Failedtoaddspace"<<*space;
}
}
}
这个函数定义在文件art/runtime/gc/collector/mark_compact.cc中。
在前面这篇文章提到,在ART运行时中,回收策略为kGcRetentionPolicyNeverCollect和kGcRetentionPolicyFullCollect的Space是ImageSpace和ZygoteSpace,因此,从这里可以看出,在Mark-CompactGC中,ImageSpace和ZygoteSpace是不进行垃圾回收的,同时也意味着NonMovingSpace、BumpPointerSpace和LargeObjectSpace需要进行垃圾回收。
MarkCompact类的成员函数MarkRoots的实现如下所示:
[cpp]viewplaincopy
voidMarkCompact:
:
MarkRoots(){
TimingLogger:
:
ScopedTimingt(__FUNCTION__,GetTimings());
Runtime:
:
Current()->VisitRoots(MarkRootCallback,this);
}
这个函数定义在文件art/runtime/gc/collector/mark_compact.cc中。
MarkCompact类的成员函数MarkRoots调用Runtime类的成员函数VisitRoots遍历当前的根集对象,并且对于每一个根集对象,都调用MarkCompact类的静态成员函数MarkRootCallback进行标记处理。
MarkCompact类的静态成员函数MarkRootCallback的实现如下所示:
[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片
voidMarkCompact:
:
MarkRootCallback(Object**root,void*arg,uint32_t/*thread_id*/,
RootType/*root_type*/){
reinterpret_cast
}
这个函数定义在文件art/runtime/gc/collector/mark_compact.cc中。
MarkCompact类的静态成员函数MarkRootCallback又是通过调用另外一个成员函数MarkObject来标记根集对象,如下所示:
[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片
inlinevoidMarkCompact:
:
MarkObject(mirror:
:
Object*obj){
......
if(immune_region_.ContainsObject(obj)){
return;
}
if(objects_before_forwarding_->HasAddress(obj)){
if(!
objects_before_forwarding_->Set(obj)){
MarkStackPush(obj);//Thisobjectwasnotpreviouslymarked.
}
}else{
......
BitmapSetSlowPathVisitorvisitor;
if(!
mark_bitmap_->Set(obj,visitor)){
//Thisobjectwasnotpreviouslymarked.
MarkStackPush(obj);
}
}
}
这个函数定义在文件art/runtime/gc/collector/mark_compact.cc中。
MarkCompact类的成员函数MarkObject首先判断对象obj是否位于非垃圾回收空间中。
如果是的话,那么不用对它进行处理了。
MarkCompact类的成员函数MarkObject接着通过成员变量objects_before_forwarding_指向的一个ContinuousSpaceBitmap来判断对象obj是否位于要进行垃圾回收和对象压缩的BumpPointerSpace中。
如果是的话,再将其在上述的ContinuousSpaceBitmap的对应位设置为1。
此外,如果对象obj是第一次被标记,那么它还被压入到MarkStack中去,以便后面可以继续对它引用的其它对象进行递归标记处理。
如果对象obj不是位于要行垃圾回收和对象压缩的BumpPointerSpace,那么这时候它肯定就是在NonMovingSpace和LargeObjectSpace中,这时候就直接对象在MarkBitmap上对应的位设置为1。
同样,如果对象是第一次被标记,那么也会被压入到MarkStack中。
根集对象标记完成之后,接下来再标记DirtyCard引用的对象,这是通过调用MarkCompact类的成员函数UpdateAndMarkModUnion实现的,如下所示:
[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片
voidMarkCompact:
:
UpdateAndMarkModUnion(){
TimingLogger:
:
ScopedTimingt(__FUNCTION__,GetTimings());
for(auto&space:
heap_->GetContinuousSpaces()){
//Ifthespaceisimmunethenweneedtomarkthereferencestootherspaces.
if(immune_region_.ContainsSpace(space)){
accounting:
:
ModUnionTable*table=heap_->FindModUnionTableFromSpace(space);
if(table!
=nullptr){
//TODO:
Improvenaming.
TimingLogger:
:
ScopedTimingt(
space->IsZygoteSpace()?
"UpdateAndMarkZygoteModUnionTable":
"UpdateAndMarkImageModUnionTable",GetTimings());
table->UpdateAndMarkReferences(MarkHeapReferenceCallback,this);
}
}
}
}
这个函数定义在文件art/runtime/gc/collector/mark_compact.cc中。
由于在Mark-CompactGC中,只有ImageSpace和ZygoteSpace是不需要进行垃圾回收的,因此这里就仅仅对它们进行处理。
在前面这篇文章提到,ImageSpace和ZygoteSpace都是有一个关联的ModUnionTable,并且通过调用这个ModUnionTable的成员函数UpdateAndMarkReferences来处理DirtyCard引用的对象。
对于DirtyCard引用的每一个对象,即DirtyCard记录的上次GC以来有修改过
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- ART运行时MarkCompact MCGC执行过程分析资料 ART 运行 MarkCompact MCGC 执行 过程 分析 资料
![提示](https://static.bdocx.com/images/bang_tan.gif)