https://www.cnblogs.com/cxy2020/p/16321884.html
https://developer.aliyun.com/article/861507
插入/刪除寫屏障都存在漏(少)回收,但是不會誤(多)回收
插入寫屏障可以認為是一個保守設計,所有新分配的堆對象如果被黑/灰對象指向都標記為灰色,在下一輪GC再回收。缺點是標記完回棧上掃一遍需要stw。
刪除寫屏障也可以認為是一個保守設計,需要所有可達根對象被標記了(期間stw)才能開啟刪除寫屏障。缺點是
為了避免內(nèi)存空間錯誤釋放,需要stw,為了不stw,推出三色不變性,負責該原則就不需要stw。
強三色不變式(對應插入寫屏障)
不允許黑色對象引用白色對象

- 插入寫屏障
具體操作:A,新增對象B且添加A->B,插入的新對象B標記為灰色。
writePointer(slot, ptr):
shade(ptr)
*slot = ptr
插入屏障僅會在堆內(nèi)存(父節(jié)點是堆對象)中生效,不對棧內(nèi)存空間生效(在棧上指向新對象時不會置黑),這是因為go在并發(fā)運行時,數(shù)十萬goroutine的棧都進行屏障保護自然會有性能問題。


弊端:由于棧上的對象沒有插入寫機制,在掃描完成后,仍然可能存在棧上的白色對象指向黑色的堆對象,所以在最后需要對棧上的空間進行STW,防止對象誤刪除。
弱三色不變式
黑色對象可以引用白色對象,但是白色對象的上游必須存在灰色對象

- 刪除寫屏障
具體操作:A->B,刪除->,則被刪除的對象B標記為灰色。
writePointer(slot, ptr):
shade(*slot)
*slot = ptr
刪除寫屏障(基于起始快照的寫屏障)有一個前提條件,就是起始的時候,把整個根部掃描一遍,讓所有的可達對象全都在灰色保護下(根黑,下一級在堆上的全灰),之后利用刪除寫屏障捕捉內(nèi)存寫操作,確保弱三色不變式不被破壞,就可以保證垃圾回收的正確性(但是需要stw)。


一個對象的引用被刪除后,即使沒有其他存活的對象引用它,它仍然會活到下一輪。如此一來,會產(chǎn)生很多的冗余掃描成本,且降低了回收精度。

混合寫屏障
插入寫屏障:結(jié)束時需要STW來重新掃描棧,標記棧上引用的白色對象的存活;
刪除寫屏障:回收精度低,GC開始時STW掃描堆棧來記錄初始快照,這個過程會保護開始時刻的所有存活對象。
GC期間,任何在棧上新創(chuàng)建的對象,均為黑色。GC剛開始的時候,會將棧上的可達對象全部標記為黑色(解除刪除寫屏障的stw)。屏障限制只在堆內(nèi)存中生效,且棧上全部標記黑色無需stw,提升了GC效率。
1、GC開始將棧上的可達對象全部掃描并標記為黑色 (之后不再進行第二次重復掃描,無需STW)
2、GC期間,任何在棧上創(chuàng)建的新對象,均為黑色。(惰性回收)(解除了刪除寫屏障的stw)
3、插入寫屏障+刪除寫屏障(堆上元素指向其他對象的時候開啟)
- 全程沒有stw