☕[JVM技術指南](4)垃圾回收子系統(Garbage Collection System)之G1垃圾收集器SATB

liboware發表於2021-06-12

物件漏標

垃圾回收的併發標記階段,gc執行緒和應用執行緒是併發執行的,所以一個物件被標記之後,應用執行緒可能篡改物件的引用關係,從而造成物件的漏標、誤標。

  • 誤標沒什麼關係,頂多造成浮動垃圾,在下次gc還是可以回收的。

  • 漏標的後果是致命的,把本應該存活的物件給回收了,從而影響的程式的正確性。

為了解決在併發標記過程中,存活物件漏標的情況,GC HandBook把物件分成三種顏色:

  1. 黑色:自身以及可達物件都已經被標記
  2. 灰色:自身被標記,可達物件還未標記
  3. 白色:還未被標記

所以,漏標的情況只會發生在白色物件中,且滿足以下任意一個條件:

  1. 併發標記時,應用執行緒給一個黑色物件的引用型別欄位賦值了該白色物件
  2. 併發標記時,應用執行緒刪除所有灰色物件到該白色物件的引用

對於第一種情況,利用post-write barrier,記錄所有新增的引用關係,然後根據這些引用關係為根重新掃描一遍

對於第二種情況,利用pre-write barrier,將所有即將被刪除的引用關係的舊引用記錄下來,最後以這些舊引用為根重新掃描一遍

SATB

SATB全稱【snapshot-at-the-beginning】,由Taiichi Yuasa為增量式標記清除垃圾收集器開發的一個演算法,主要應用於垃圾收集的併發標記階段,解決了CMS垃圾收集器重新標記階段長時間STW的潛在風險。

Region包含了5個指標,分別是bottom、previous TAMS、next TAMS、top和end

☕[JVM技術指南](4)垃圾回收子系統(Garbage Collection System)之G1垃圾收集器SATB

其中previous TAMS、next TAMS是前後兩次發生併發標記時的位置,全稱top-at-mark-start

  1. 假設第n輪併發標記開始,將該Region當前的top指標賦值給next TAMS,在併發標記標記期間,分配的物件都在[next TAMS, top]之間,SATB能夠確保這部分的物件都會被標記,預設都是存活的

  2. 當併發標記結束時,將next TAMS所在的地址賦值給previous TAMS,SATB給 [bottom, previous TAMS] 之間的物件建立一個快照Bitmap,所有垃圾物件能通過快照被識別出來

  3. 第n+1輪併發標記開始,過程和第n輪一樣

SATB保證了在併發標記過程中新分配物件不會漏標

  • 但如果在TAMS之前有一個白色物件W,被一個灰色物件G引用,在併發標記掃描到這個欄位之前被賦值為null,切斷了物件W和物件G之間的引用關係,物件W就有可能漏標,這就是白色物件被漏標的第二種情況?

G1中如何解決?

在引用關係被修改之前,插入一層 pre-write barrier

☕[JVM技術指南](4)垃圾回收子系統(Garbage Collection System)之G1垃圾收集器SATB

pre-write barrier最終執行邏輯:

☕[JVM技術指南](4)垃圾回收子系統(Garbage Collection System)之G1垃圾收集器SATB

通過G1SATBCardTableModRefBS::enqueue(oop pre_val)把原引用儲存到satb mark queue中,和RSet的實現類似,每個應用執行緒都自帶一個satb mark queue.

在下一次的併發標記階段,會依次處理satb mark queue中的物件,確保這部分物件在本輪GC是存活的。

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章