聊聊ShenandoahGC的Brooks Pointers


本文主要研究一下ShenandoahGC的Brooks Pointers
Shenandoah
Shenandoah面向low-pause-time的垃圾收集器,它的GC cycle主要有

Snapshot-at-the-beginning concurrent mark包括Init Mark(Pause)、Concurrent Mark、Final Mark(Pause)

Concurrent evacuation(这个阶段用到了Brooks Pointers(object version change with additional atomically changed indirection)进行copy)
Concurrent update references (optional)包括Init update Refs(Pause)、Concurrent update Refs、Final update Refs(Pause)

其中Final Mark或者Final update Refs之后都可能进行Concurrent cleanup,进行垃圾回收,reclaims region
Brooks Pointers
G1 GC在evacuation阶段是parallel的,但不是concurrent,ShenandoahGC为了做到concurrent copy使用了Brooks Pointers。
Rodney A. Brooks在<<Trading Data Space for Reduced Time and Code Space in Real-Time Garbage Collection on Stock Hardware>>这篇论文提出了一种使用forwarding pointer来做到concurrent copy的方案,该方案在所有对象的内存结构上新增一个forwarding pointer,它要么指向对象自己,要么指向在to-region的自己的拷贝
其要点如下:

evacuation的第一步是拷贝from-region的对象到to-region
evacuation的第二步使用CAS改变from-region的对象的forwarding pointer由自己变为指向to-region的拷贝对象
evacuation的第三步就是遍历heap,更新引用到to-region的拷贝对象

如果在evacuation期间,其他线程通过旧的引用访问到了from-region的旧对象,它就需要根据旧对象的forwarding pointer找到to-region的拷贝对象;等所有旧对象的引用都更新完之后,后续就可以回收from-region的旧对象
示例代码
concurrent copy
class VersionUpdater<T, V> {
final AtomicReference<T> ref = …;
void writeValue(V value) {
do {
T oldObj = ref.get();
T newObj = copy(oldObj);
newObj.set(value);
} while (!ref.compareAndSet(oldObj, newObj));
}
}
这里使用do while循环,即先拷贝再进行CAS,如果CAS不成功则继续尝试拷贝和CAS
write barriers
stub Write(val, obj, offset) {
if (evac-in-progress && // in evacuation phase
in-collection-set(obj) && // target is in from-space
fwd-ptrs-to-self(obj)) { // no copy yet
val copy = copy(obj);
*(copy + offset) = val; // actual write
if (CAS(fwd-ptr-addr(obj), obj, copy)) {
return; // success!
}
}
obj = fwd-ptr(obj); // write to actual copy
*(obj + offset) = val; // actual write
}
在evacuation阶段,对from-region的对象的写操作会触发该对象的evacuation操作(如果该对象在to-region还没有copy的话)
evacuation
stub evacuate(obj) {
if (in-collection-set(obj) && // target is in from-space
fwd-ptrs-to-self(obj)) { // no copy yet
copy = copy(obj);
CAS(fwd-ptr-addr(obj), obj, copy);
}
}
evacuate先判断该对象是否在from-region且在to-region还没有copy,如果满足条件则进行拷贝,然后CAS修改旧对象的forwarding pointer指向拷贝对象
小结

Shenandoah面向low-pause-time的垃圾收集器,它在Concurrent evacuation阶段用到了Brooks Pointers(object version change with additional atomically changed indirection)进行copy,以实现concurrent copy
Rodney A. Brooks在<<Trading Data Space for Reduced Time and Code Space in Real-Time Garbage Collection on Stock Hardware>>这篇论文提出了一种使用forwarding pointer来做到concurrent copy的方案,该方案在所有对象的内存结构上新增一个forwarding pointer,它要么指向对象自己,要么指向在to-region的自己的拷贝
evacuation的第一步是拷贝from-region的对象到to-region;evacuation的第二步使用CAS改变from-region的对象的forwarding pointer由自己变为指向to-region的拷贝对象;evacuation的第三步就是遍历heap,更新引用到to-region的拷贝对象

doc

forwarding pointer
Shenandoah: A pauseless GC for OpenJDK
Shenandoah GC: An overview
Shenandoah GC: Concurrent parallel marking
Shenandoah GC: Brooks pointers

devoxx-Nov2017-shenandoah(示例代码来源于此pdf)

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理