併發三色標記法
三色:黑、灰、白
- 黑對象代表,對象自身存活,且其指向對象都已標記完成
- 灰對象代表,對象自身存活,但其指向對象還未標記完成
- 白對象代表,對象尙未被標記到,可能是垃圾對象
標記過程:
- 初始化:所有對象都被標記為白色
- 將根對象(全局對象、棧上局部變量等)置黑,將其所指向的對象置灰
- 從灰對象出發,將其所指向的對象都置灰. 所有指向對象都置灰後,當前灰對象置黑
- 標記結束後,白色對象就是不可達的垃圾對象,需要進行清掃
可能產生的問題
- 漏標 ->屏障機制
在某個對象標記為黑色之後,它新指向了一個對象,可能該對象之前被某灰色對象標記,還未掃描到,灰色對象就刪除了對該對象的指向
- 多標 ->下一輪GC
在標記完一個灰色對象時,刪除了指向它的黑色對象對它的引用
屏障機制
強弱三色不變式
- 強三色不變式:白色對象不能被黑色對象直接引用
- 弱三色不變式:白色對象可以被黑色對象引用,但要從某個灰對象出發仍然可達該白對象
插入寫屏障
屏障機制類似於一個回調保護機制,指的是在完成某個特定動作前,會先完成屏障成設置的內容,插入寫屏障(Dijkstra)的目標是實現強三色不變式,當一個對象引用另一個對象時,將被引用的對象標記為灰色。
刪除寫屏障
刪除寫屏障(Yuasa barrier)的目標是實現弱三色不變式,保證當一個白色對象即將被上游刪除引用前,會觸發屏障將其置灰,之後再刪除上游指向其的引用。
混合寫屏障
通過結合這兩種寫屏障技術,Go 的垃圾回收器可以在併發標記階段運行,而無需停止整個程序(Stop-the-World)。
插入寫屏障和刪除寫屏障的短板:
- 插入寫屏障:結束時需要STW來重新掃描棧,標記棧上引用的白色對象的存活;
- 刪除寫屏障:回收精度低,GC開始時STW掃描堆棧來記錄初始快照,這個過程會保護開始時刻的所有存活對象。
混合寫屏障操作:
- GC 開始前,以棧為單位分批掃描,將棧中所有對象置黑
- GC 期間,棧上新創建對象直接置黑
- 堆對象正常啓用插入寫屏障(添加的對象置為灰色)
- 堆對象正常啓用刪除寫屏障(被刪除引用的對象被標記為灰色)