? ? ? ?在 JVM 并發垃圾收集(GC)中,三色標記算法是實現 “GC 線程與用戶線程并行執行” 的關鍵技術,它解決了并發場景下 “如何準確標記存活對象” 的核心問題,是 CMS、G1 等現代收集器的底層基礎。
一、三色標記的核心:三種顏色的定義與狀態
算法通過 “顏色” 標記對象的標記階段和存活狀態,共三種顏色,對應不同角色:
顏色 | 名稱 | 核心定義 |
---|---|---|
白色 | 未標記 | 初始狀態,對象尚未被 GC 線程訪問。標記結束后仍為白色,判定為 “死亡對象”(可回收)。 |
灰色 | 待處理 | 對象已被 GC 線程訪問,但該對象的所有子引用尚未遍歷(后續需繼續處理子對象)。 |
黑色 | 已處理 | 對象已被 GC 線程訪問,且該對象的所有子引用都已遍歷完成(后續無需再處理)。 |
二、并發標記的核心問題:漏標與錯標
并發標記時,用戶線程會修改對象引用關系,導致兩種關鍵問題,其中漏標是必須解決的致命錯誤:
1. 漏標(Missing Mark):存活對象被誤判為死亡
- 觸發場景:白色對象(未標記)被黑色對象(已處理,不再遍歷)引用,且原引用它的灰色對象(待處理)的引用被刪除。
- 危害:漏標會導致存活對象被錯誤回收,直接引發空指針異常,是致命問題。
2. 錯標(False Mark):死亡對象被誤判為存活
- 觸發場景:本應死亡的白色對象,被其他白色對象新增引用,導致標記結束后被誤判為存活。
- 影響:僅造成暫時內存泄漏,后續 GC 會重新判斷并回收,屬于可接受的誤差。
三、解決漏標的兩大方案
工業界通過兩種成熟方案避免漏標,核心思路是 “記錄關鍵引用變更,確保白色對象被正確標記”:
1. 增量更新(Incremental Update):記錄新增引用
- 核心邏輯:當黑色對象(已處理)新增對白色對象的引用時,通過 “寫屏障” 記錄該引用,后續重新遍歷這個白色對象。
- 通俗理解:黑色對象不能 “偷偷” 引用白色對象,所有新增引用必須 “報備”,確保白色對象被標記。
- 應用:CMS 收集器采用此方案,在 “重新標記” 階段(短暫 STW)遍歷記錄的引用,修正標記。
2. 原始快照(SATB):記錄刪除引用
- 核心邏輯:當灰色對象(待處理)刪除對白色對象的引用時,通過 “寫屏障” 記錄該刪除的引用(視為 “快照”),后續仍會遍歷這個白色對象。
- 通俗理解:灰色對象刪除的引用要 “記下來”,即使引用沒了,也要確保白色對象不會漏標。
- 應用:G1 收集器采用此方案,在 “最終標記” 階段(短暫 STW)處理快照引用,修正結果。
四、總結
三色標記算法通過 “顏色劃分對象狀態”,解決了并發 GC 的標記準確性問題:
- 三種顏色清晰界定對象的 “未標記 - 待處理 - 已處理” 狀態;
- 漏標是致命問題,需通過增量更新(CMS 用)或原始快照(G1 用)解決;
- 錯標影響較小,可通過后續 GC 彌補。