Card Table 卡表

因何而生

現代JVM,堆空間通常被劃分爲新生代和老年代。由於新生代的垃圾收集通常很頻繁,如果老年代對象引用了新生代的對象,那麼,需要跟蹤從老年代到新生代的所有引用,從而避免每次YGC時掃描整個老年代,減少開銷。

對於HotSpot JVM,使用了卡標記(Card Marking)技術來解決老年代到新生代的引用問題。具體是,使用卡表(Card Table)和寫屏障(Write Barrier)來進行標記並加快對GC Roots的掃描。

底層設計

基於卡表的設計,通常將堆空間劃分爲一些列2次冪大小的卡頁(Card Page)。卡表用於標記卡頁的狀態,每個卡表對應一個卡頁。

HotSpot JVM的卡頁大小爲512字節,卡表被實現爲一個簡單的字節數組,即卡表的每個標記項爲1個字節。當對一個對象引用進行寫操作時(對象引用改變),寫屏障邏輯將會標記對象所在的卡頁爲dirty。

OracleJDK/Oracle 1.6/1.7.1.8 JVM默認的卡標記簡化邏輯如下:

CARD_TABLE [this address >>9] =0;

首先,計算對象引用所在卡頁的卡表索引號,將地址右移9位,相當於用地址除以512,假設卡表卡頁的其實地址爲0 ,那麼卡表項 0、1、2對應的卡頁起始地址分別爲 0 ,512,1024 (卡表項索引號誠意卡頁512字節),其次通過卡表索引號,設置對應標識爲dirty。

固有問題

  • 無條件寫屏障帶來的性能開銷

    每次對引用的更新,無論是否更新了老年代對新生代對象的引用,都會進行一次寫屏障操作。顯然,這會增加一些額外的開銷。但是,與YGC時掃描整個老年代相比較,這個開銷就低得多了。不過,在高併發環境下,寫屏障又帶來了虛共享(false sharing)問題。

  • 高併發下虛共享帶來的性能開銷(false sharing)

在高併發下,頻繁的寫屏障很容易發生虛共享(false sharing),從而帶來性能開銷。假設CPU緩衝行大小爲64字節,由於一個卡表項佔一個字節,這意味64個卡表項將共享一個緩存行。

HotSpot 每個卡頁爲512字節,那麼一個緩存行將對應64個卡頁,一共64*512 =32k ,

如果不同線程堆對象引用的更新操作,恰好謂語同一個32kb區域,這將導致同時更新卡表的同一個緩衝行,從而造成緩衝行的寫回無效化或者同步操作,間接影響程序性能。

一個簡單的解決方案,就是不採用無條件的寫屏障,而是先堅持卡表標記,只有當該卡表項未被標記過纔將其標記爲dirty。

這就是JDK 7中引入的解決方法,引入了一個新的JVM參數-XX:+UseCondCardMark,在執行寫屏障之前,先簡單的做一下判斷。如果卡頁已被標識過,則不再進行標識。

if (CARD_TABLE [this address >> 9] != 0)
  CARD_TABLE [this address >> 9] = 0;

與原來的實現相比,只是簡單的增加了一個判斷操作。

雖然開啓-XX:+UseCondCardMark之後多了一些判斷開銷,但是卻可以避免在高併發情況下可能發生的併發寫卡表問題。通過減少併發寫操作,進而避免出現虛共享問題(false sharing)。

也用於CMS GC

CMS在併發標記階段,應用線程和GC線程是併發執行的,因此可能產生新的對象或對象關係發生變化,例如:

  • 新生代的對象晉升到老年代;

  • 直接在老年代分配對象;

  • 老年代對象的引用關係發生變更;

  • 等等。

對於這些對象,需要重新標記以防止被遺漏。爲了提高重新標記的效率,併發標記階段會把這些發生變化的對象所在的Card標識爲Dirty,這樣後續階段就只需要掃描這些Dirty Card的對象,從而避免掃描整個老年代。

應用場景

JVM虛擬機用了一個叫做CardTable(卡表)的數據結構來標記年輕代的某一塊內存區域中對象是否持有新生代對象的引用,卡表的數量取決於老年代的代銷和每張卡對應的內存大小,每張卡在卡表中對應一個比特位,當老年代中某個對象持有了新生代對象的引用時,JVM就會把這個對象的Card所在的位置標記爲dirty(bit位設置爲1),這樣在Minor GC時,就不需要掃描整個老年代,而是掃描Card中dirty對應的那些區域。

由於在做YGC時,需要掃描整個Old 區,效率非常低,所以JVM設計了CardTable,如果一個Old區CardTable 中有對象指向Y區,下次掃描的時候需要掃描Dirty Card,Dirty Card 記錄了這些對象在內存區域是clean 還是dirty狀態,在結構上Card Table用BitMap來實現。

 

參考:https://blog.csdn.net/weixin_33896726/article/details/88014774

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