本文主要研究一下ShenandoahGC的Brooks Pointershtml
Shenandoah面向low-pause-time的垃圾收集器,它的GC cycle主要有bash
包括Init Mark(Pause)、Concurrent Mark、Final Mark(Pause)
這個階段用到了Brooks Pointers(
object version change with additional atomically changed indirection)進行copy
)包括Init update Refs(Pause)、Concurrent update Refs、Final update Refs(Pause)
其中Final Mark或者Final update Refs以後均可能進行Concurrent cleanup,進行垃圾回收,reclaims regionless
G1 GC在evacuation階段是parallel的,但不是concurrent,ShenandoahGC爲了作到concurrent copy使用了Brooks Pointers。wordpress
Rodney A. Brooks在<>這篇論文提出了一種使用forwarding pointer來作到concurrent copy的方案,該方案在全部對象的內存結構上新增一個forwarding pointer,它要麼指向對象本身,要麼指向在to-region的本身的拷貝ui
其要點以下:atom
若是在evacuation期間,其餘線程經過舊的引用訪問到了from-region的舊對象,它就須要根據舊對象的forwarding pointer找到to-region的拷貝對象;等全部舊對象的引用都更新完以後,後續就能夠回收from-region的舊對象spa
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.net
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的話
)線程
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指向拷貝對象code
object version change with additional atomically changed indirection
)進行copy,以實現concurrent copy