JVM GC:OopMap、CardTable、RememberedSet

2017-07-19

JVM GC:OopMap、CardTable、RememberedSet

[以下內容適用於 Hotsport JVM]

一句話概括:OopMap 用於枚舉 GC Roots 和 準確式 GC,CardTable 和 RememberSet 用於可達性分析。

OopMap

JVM GC 判斷對象是否可以回收使用可達性分析的方法,可達性分析首先需要找到 GC Roots 對象。

Java 中有幾種 GC Root:
1)虛擬機棧(棧幀中的局部變量表)中引用的對象【Stack Local】

OopMap 是一個映射表,記錄了棧上本地變量到堆上對象的引用關係,用來判斷所有位置上的數據是不是指向堆中的引用。

垃圾收集時,收集線程會對棧上的內存進行掃描,如果發現某個位置存的是引用類型,那麼引用的對象暫時不能被回收。但是,棧上的本地變量表裏面只有一部分數據是引用類型的,那些非引用類型的數據不需要關心。OopMap 就是一種空間換時間的方法,存儲這些引用關類型的位置,在 GC 的時候只需要讀取 OopMap 上的信息。

每個線程對應着一個棧,一個棧由多個棧幀組成,每個棧幀對應一個方法,一個方法裏面可能有多個安全點(Safepoint)。GC 發生時,線程運行到最近的一個安全點停下來,然後更新自己的 OopMap 。遍歷每個棧幀的 OopMap,通過記錄的被引用對象的內存地址,即可找到這些 GC Roots。

OopMap 可以避免全棧掃描,加快找到 GC Roots 的速度。但是它的更根本的作用是,可以幫助 HotSpot 實現準確式 GC 。關於準確式 GC 的更多內容:https://rednaxelafx.iteye.com/blog/1044951

CardTable

將老年代的空間分成大小爲 512bytes 的塊,有一個叫 Card Table 的數組結構存儲(每個位置存的是一個byte),數組的每一位對應老年代空間中的一個塊。
併發標記時,如果某個對象的引用發生了變化,Card Table 就標記該對象所在的塊爲 Dirty Card。

在GC時,Dirty Card 相當於 GC roots,可到達的新生代對象/老年代對象也是活的。

RememberedSet

一般來說,新生代 GC 過程是這樣的:首先枚舉根節點。根節點有可能在新生代中,也有可能在老年代中。這裏由於我們只想收集新生代,所以沒有必要對位於老年代的 GC Roots 做全面的可達性分析。但問題是,確實可能存在位於老年代的某個 GC Root,它引用了新生代的某個對象,這個對象你是不能清除的。那怎麼辦呢?

仍然是拿空間換時間的辦法。對於位於不同年代對象之間的引用關係,虛擬機會在程序運行過程中給記錄下來。對應上面所舉的例子,“老年代對象引用新生代對象”這種關係,會在引用關係發生時,在新生代邊上專門開闢一塊空間記錄下來,這就是 RememberedSet 。所以新生代的 GC Roots + RememberedSet 存儲的內容,是新生代收集時真正的 GC Roots 。

G1 把一塊大的內存劃分成很多個域( Region )。總會存在一個 Region 中的對象引用另一個 Region 中對象的情況。爲了達到可以以 Region 爲單位進行垃圾回收的目的, G1 收集器也使用了 RememberedSet 這種技術,在各個 Region 上記錄自身的對象被外面對象引用的情況。


References:
《深入 Java 虛擬機》
https://dsxwjhf.iteye.com/blog/2201685
https://rednaxelafx.iteye.com/blog/1044951
http://www.wannengye.com/pages/Mwh1g9FU/?from=timeline&isappinstalled=0

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章