JVM 垃圾回收器 ZGC

JAVA內存模型

在這裏插入圖片描述
在這裏插入圖片描述

JVM線程
  • OSThread
    JVM 對不同系統的線程抽象
  • Thread
    Thread 是 C++ 定義的線程基類,除了 OSThread 類,作爲其他線程的基類,它包含了 OSThread 對象的指針
  • JavaThread:
    Java 層創建的線程
    CompilerThread :C1 CompilerThread 和C2 CompilerThread
  • VMThread:
    單例原生線程VMThread
    維護一個vm操作隊列(VMOperationQueue):GC,heapdump。
    VM_CMS_Operation
    VM_CGC_Operation
    VM_GC_Operation
  • WorkerThread
    子類GCTaskThread、GangWorker是用來執行gc任務的

在這裏插入圖片描述

Parallel:VMThread和GCTaskThread

在這裏插入圖片描述

CMS:VMThread和GangThread

在這裏插入圖片描述

ZGC:ZWorker和RuntimeWorker

在這裏插入圖片描述

JVM線程-Stop The Word

Stop the World 是JVM等待所有的用戶線程進入safepoint並且阻塞,做一些全局性操作的行爲。

  1. JIT相關
  2. Class redefinition
  3. 取消偏向鎖 ;
  4. Various debug operation
    -XX:+PrintGCApplicationStoppedTime系統停頓時間
    -XX:+PrintSafepointStatistics
    -XX: PrintSafepointStatisticsCount=1
什麼是ZGC

A Scalable Low Latency Garbage Collector-可伸縮的低延遲垃圾收集器
目標:
1,TB級別內存(最多4TB)
2,最大10ms的暫停時間(STW)
3,最大15%的應用吞吐量減低
4,支持NUMA
特點
1,不支持分代,僅支持Linux 64位系統
2,設計了分頁管理支持TB級內存,
3,快速的進行併發標記和併發移動(Color Pointers)
4,設計了讀屏障,實現了增量標記
5,設計了物理內存和虛擬內存兩級內存管理

GC屏障 (GC Barriers)
Write Barrier:往堆寫入引用時,GC需要執行一些額外操作,對於在Java中:obj.field=xxx。常見於分代GC,比如老年代引用新生代,會維護card table。G1在維護Rset的時候使用了write barrier
Load barrier:在從堆讀取引用時,GC需要執行一些額外操作。對於在Java中,也就是像執行這樣的代碼Object xxx=obj.field時才需要額外操作。
ZGC的Load Barrier的作用:
運用在從堆裏面加載對象,而不是在後續訪問對象時。
判斷指針的當前顏色。如果是壞顏色,就修復它。

Heap Regions
堆的分區又被稱作ZPages
1,動態創建和銷燬,
2,動態大小,都是2M的整數倍(目前對x86_64)。
3,ZGC有3種不同的頁面類型:
小型 (2MB大小)
中型 (32MB大小)
大型 (2MB的倍數):大於4MB的一個對象。
4,區分物理內存和虛擬內存。
足夠的虛擬內存(ZGC總是4TB)
物理內存可以擴展到最大堆大小(使用-Xmx設置)

在這裏插入圖片描述

着色指針Colored Pointers
ZGC不支持compressed oops和32位系統平臺。因爲部分元數據存放在64指針之中
前42位爲定位對象地址的,緊接着4位分別爲finalizable , remapped , marked1和marked0 標誌位。更高的位目前都是0。
通過marked1和marked0判斷是否被標記
通過remapped知道沒有指向重定位後的集合中
通過finalizable判斷是否只能通過Finalizer才能訪問到。
讀屏障可以實現對象的在這裏插入圖片描述##### ZGC過程-標記階段

  • 標記階段
    Live Map是一個位圖(bitmap) ,用於存儲給定索引處的對象是否可達和/或最終可達。
    ZGC把內存分爲多個Striped,Striped在多個線程上進行分配,每個線程負責各自的Striped,當一個線程完成時,也會處理其他現在未完成的Striped
    在這裏插入圖片描述

  • 標記階段-初始標記
    第一階段是STW,其中GC roots被標記爲活對象。
    如果一個對象不能通過遍歷從roots開始的對象圖來訪問,那麼應用程序也就無法訪問它,則該對象被認爲是垃圾。從roots訪問的對象集合稱爲Live集(live-set)。GC roots標記步驟非常短,因爲roots的總數通常比較小。
    在這裏插入圖片描述

  • 標記階段-併發標記
    初始標記階段完成後,應用程序恢復執行,ZGC開始下一階段.
    該階段同時遍歷對象圖並標記所有可訪問的對象。
    應用程序線程中的load-barrier讀屏障針使用掩碼測試所有已加載的引用,該掩碼確定它們是否已標記或尚未標記,將未標記的引用推送到線程局部標記緩衝區。只要此緩衝區已滿,GC線程就可以獲得此緩衝區的所有權,並以遞歸方式遍歷此緩衝區中的所有可到達對象。在應用程序線程中標記只是將引用推送到緩衝區,GC線程負責遍歷對象圖並更新Live map.

  • 標記階段-標記結束
    在遍歷完成之後,有一個最終的,時間很短的的Stop The World階段,清空緩存區,解決併發階段引用變化的情況。

ZGC過程-重定位階段

重定位階段-選擇重定位pages
重定位前,此時需要解決的問題是要重定位哪些pages,稱爲Relocation Set。
生成了forwarding tables記錄指針變化。
在這裏插入圖片描述 - 定位階段-重定位roots
選擇重定位集後,會出現一個Stop The World暫停,其中ZGC重定位該集合中root對象,並將他們的引用映射到新位置。
遍歷所有的roots,並進行遷移,指針記錄到forwarding tables

在這裏插入圖片描述

(1)重定位階段-重定位roots指向的對象
移動root後,下一階段是併發重定位。
在此階段,GC線程遍歷重定位集並重新定位其包含的頁中所有對象。
如果應用程序線程試圖在GC重新定位對象之前加載它們,那麼應用程序線程也可以重定位該對象,這可以通過讀屏障(在從堆加載引用時觸發)實現。
一旦一個page已經沒有元素了,此時它就可以馬上被重新使用。不用等到GC所有階段結束。
在這裏插入圖片描述

(2)重定位階段-重定位root指向的對象
同時注意,此時其他指向5的對象指針仍然沒有變,當這些對象需要訪問5時如果不做特殊處理就會出錯,這就是load barrier的作用,它會讓當前對象對5的引用重新指向新的地址。

在這裏插入圖片描述
重定位階段結束,同時也意味着到此時,GC週期結束。但是就會發現上面還有部分指針沒有remap到正確的位置。如果需要進行修復,那也要進行一次全部遍歷。如下圖:進行一次併發重映射。
但是就會發現,第一個併發標記和最後的併發重映射都是一個對象遍歷,所有這兩個階段可以合併。合併就設計到一個問題,怎麼判斷當前的引用是上次GC循環沒有remap的呢?這就需要一個標誌,這也就是引用標誌中有兩位特殊的標誌位marked1和marked2。
在這裏插入圖片描述

JDK 11中ZGC的不足

1,實驗性質
2,ZGC僅實現了單代內存管理,也就是說沒有考慮熱點數據與冷數據,這個在商業的C4已經支持。
3,C2的支持還不夠完善;
4,不支持Graal, HDSB等功能
5,ZGC並不是下一代GC唯一的發展方向:Shenandoah

http://ju.outofmemory.cn/entry/367911
https://blog.csdn.net/qq_42882671/article/details/82622328
https://blog.longyb.com/2018/10/04/Zgc_Introduction/
https://dinfuehr.github.io/blog/a-first-look-into-zgc/
過程概覽地址:http://hg.openjdk.java.net/zgc/zgc/file/59c07aef65ac/src/hotspot/share/gc/z/zDriver.cpp#l316

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