ZGC回收器到底有多變態?

zgc是個什麼東東?簡單說是個垃圾回收器。算法

一個低延遲的垃圾回收器!微信


多少年來,JVM中的各類垃圾回收器都在努力追求着兩個目標,暫停時間足夠短,同時吞吐量也要不錯。爲了追求兩者兼具,各類垃圾回收器可謂絞盡腦汁,但仍是沒法同時讓兩個都足夠好,要麼暫停時間縮短了但吞吐量降低了,要麼吞吐量上去了暫停時間卻變長了,真的是操蛋,即便是如今最新的生產可用的G1也是,雖然他也號稱是low latency,也能夠指定暫停時間,但仍是須要你去平衡暫停時間和吞吐量,G1能夠說是很是努力了,但仍是沒有作到極致和傻白甜。併發


但事情老是發展的,前幾天,jdk11的開發團隊悄悄的在本身的功能列表中添加了一個叫ZGC的gc。沒錯,就是咱們今天要侃的主角,一個集暫停與吞吐於一身的回收器,聽着就是否是被嚇尿了,是否是感受之後都不用對JVM調優了,是否是之後代碼能夠xjb寫了。app


來看看它的目標:佈局


看看這些目標!
性能


TB級的堆隨便搞!暫停時間10毫秒內!吞吐量最大降低15%!大聲告訴我,嚇尿沒?!優化


好,繼續。spa

暫停時間不會隨着堆的增大而變長!不會!操作系統


整體印象.net


好,接下來,咱們仍是先對ZGC有個整體上的印象。


一、全新的垃圾回收器。「全新」指的是一點點從草稿而後搞出來,不是基於哪一個來優化出來的。

二、使用了Load Barriors技術,而不是使用store Barriors。這是兩種不一樣的技術。store barriors是hotspot裏現存的好多垃圾回收器所用的技術。zgc中使用load barrior技術來跟蹤堆的狀態和對象的狀態。

三、單代。它是一個只有一個generation的回收器。

四、Partial Compaction。也是基於部分壓縮,這個和G1是同樣的。

五、Region-Based GC。它有點像G1,都是基於region,但和G1不同的是,zgc有更加靈活的region的size schema。這樣咱們就能夠輕鬆的處理大對象的分配問題了。

六、Immediate Memory Reuse。zgc和G1同樣,region們會被及時的清理和壓縮和轉移,可讓內存的複用更加的及時。

七、NUMA-aware。這是一種內存頁合併的硬件技術。

八、Colored Object Pointers。

九、Concurrent。zgc一個很是重要的能力。就是並行和併發幹幾乎全部的事情。

好比:

  • 一、Marking。

  • 二、Relocation和Compaction。

  • 三、Relocation Set Selection。

  • 四、Reference Processing。

  • 五、JNI WeakRefs Cleaning。

  • 六、StringTable和SymbolTable Cleaning。

  • 七、Class Unloading。

以上這些通通併發(conccurent)搞!zgc團隊爲他們的這一項能力很是驕傲,這在open jdk的其餘垃圾回收器是很是少有的。

目前的狀態


一、ZGC目前僅支持Linux/x86_64。

二、性能方面目前是很是牛x的。不管是暫停時間仍是吞吐量。


看看一些數字


這是評測結構跑的分數。重點看看藍色的指標,能夠看出ZGC要比Parallel和G1要更好。


再來看看暫停時間的分數:



是否是很誇張。暫停時間遠低於他們最初定的目標10ms


GC階段


這裏先放個圖,先有個印象,後面會有一個gc過程示例來詳細說明。


Heap Regions


堆區域。也被稱爲:ZPages。


這和G1的region有點像,但和G1不同的是,region的大小更加靈活和動態。zgc的region不會像G1那樣在一開始就被劃分爲固定大小的region。


zgc的region核心亮點就是:動態。


動態表現爲:

  • 一、動態地建立和銷燬。

  • 二、動態地決定region的大小。它的最小單位是2MB的一個塊。而後每一個region的大小就是是2MB*N就是。


並且他有個概念叫:size groups。有三種:


Small:就是一個2MB的region。

Medium:32mb。2MB*16。

Large:N*2MB。


整個heap長這樣:



Colored Pointers


是zgc的一個核心概念。你還能夠叫它tag pointers,version pointers。


metadata被保存在64-bit的pointer中。目前不支持32位的平臺。也不支持CompressedOops。


Virtual Address-masking能夠是硬件或操做系統或軟件。


先來看看在x86_64上的colored pointer的佈局:

一個pointer共64bit。開始的18bit暫時沒有被用到(之後有可能要用),而後是四個bit,分別表示Finalizable、Remapped、Marked一、Marked0,這是gc過程當中每一個對象的狀態。最後42bit是用來存儲對象的地址。

當是remapped時候,表示不要指向到relocation set(具體relocation set是個什麼會在後面的gc示例中說到)中。

當顏色爲Finalizable的時候,就只能經過Finalizer來訪問到,其餘的途徑已沒法訪問。

Linux/x86_64上是Heap Multi-Mapping


下面是在x86_64上的heap中的address space中的pointer們的邏輯映射。

在Solaris/SPARC的heap映射:

Solaris/SPARC上是single heap mapping


Load Barrier


Load Barrier主要用於在對象從heap load的時候。並且只在這一個地方用到load barrier。一旦你過了load barrier併成功的拿到了對象,以後你就能夠任意的使用它了,好比訪問字段,調用方法等。爲何要加入load barrier呢?它的主要目的就是檢查pointer是否是「bad color」(前面咱們講到colored pointers)。若是是一個bad color的pointer,那麼就須要走一個慢的路徑(slow path),而後採起一些措施而後讓他變成good color,而後下次你在load的時候,就會走快的路徑(fast path),而不須要作額外的措施了。


bad color:mark 、relocate、remap。

good color:repair、heal。


大部分的狀況下的對象引用都是good color。


來看看一個例子:



具體的load barrier實現:



若是不是good color而且對象不爲null,那麼執行slow_path:



GC過程示例


接下來展現一下zgc中的gc過程。


開始示例以前,先說明下,本圖的基本元素。含有箭頭的線條咱們稱之爲:pointer。而後每一個數字表示object。每一個方塊表示一個region。


首先從roots開始一直往下連通,若是可以直接連通的,咱們認爲就是可達的,而後標記爲紅色。


Pause Mark Start


而後標記1爲紅色,表示ok。

而後標記2爲紅色。

而後標記4爲紅色。


Concurrent Mark




如今標記結束了。接下來進入的階段是「從新分配準備階段」:Concurrent Prepare for Relocate。


Relocation就是一個轉移的過程。


標記事後,咱們發現3,6,7是不一樣的顏色。


Concurrent Prepare for Relocate


標記事後,就須要肯定哪些region中的對象被轉移。能夠發現含有三、六、7的兩個region被列爲了Relocation Set,意味着這兩個region中的對象將會被relocation。

那麼四、五、8要被轉移到哪裏呢?

接下來進入Pause Relocate Start階段。


Pause Relocate Start


綠色表示Remapped+Relocate的過程。

當來到4的是,發現它屬於Relocation Set的對象,因而把4轉移到了最右邊的那個全新的region中。而後在下面的Forwarding Table中作個記錄。

而後進入到Concurrent Relocate階段。把4轉移了?那5和8怎麼辦呢?


Concurrent Relocate


這個階段,負責5和8轉移到4如今所在的那個region。

如今5已經被轉移到了新region。原來三、四、5所在region已經被清理空了,能夠從新被使用了。以下:

一樣的作法,把8也轉移到新的region裏。

一樣的又一個region被騰空了,能夠被從新使用了。


GC Cycle Completed



好,是否是發現2和5已經沒法連通了。接下來進入第二階段的Pause Mark Start。


Pause Mark Start  (Second Cycle)




Concurrent Mark (Second Cycle)



Pause Mark End (Second Cycle)



Concurrent Prepare for Relocate (Second Cycle)


能夠發現Forwarding Table已被清空。


Stripe Mark


好,你也許好奇,那麼多的region,zgc是怎麼進行一個個進行回收的呢?上面只是展現了幾個對象而已,幾個region而已。


這裏就要說到zgc的一個宏觀的條紋標記技術:Striped Mark。光聽到這名詞,你也許不知道具體是怎麼作的。



這就是條紋,每一個條紋的顏色不一樣。


條紋標記法會把heap邏輯上分紅若干個條紋組。而後把每一個gc線程都隔離到它本身的stripe上進行gc。



如今假設有四個GC線程。而後Heap如上所示。


而後把heap分爲不一樣顏色的條紋。



而後再抽象一層stripe分組。



不一樣顏色的條紋由不一樣的線程來處理。



但有種狀況是有的GC線程提早完成了本身所在stripe的清理工做。此時它會加入到其餘的stripe上繼續幫助其餘的gc線程繼續清理其餘的stripe(這個思路有點相似工做竊取算法)。



好,以上就是所有。ZGC,一個集暫停與吞吐於一身的GC,一個暫停時間控制在10毫秒之內的GC!



說點什麼

  • 微信公衆號(歡迎調戲): battcn

本文分享自微信公衆號 - battcn(battcn)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索