JDK 15中Z垃圾收集器演算法 - JesúsNavarrete

發表於2020-12-12

隨著JDK 15釋出,最新版本的ZGC現在可以投入生產了。簡而言之,ZGC是一個可伸縮的低延遲垃圾收集器,最大GC暫停時間為10毫秒,能夠處理從幾兆位元組到多TB的堆,最大吞吐量降低了15%。

 

JVM垃圾收集器

到目前為止,JVM引入了一個有趣的垃圾收集器演算法列表,下面列出了最重要的演算法和簡短的描述,讓我們記住它們。

  • 序列(低記憶體佔用):它使用單個執行緒來完成工作。它適用於單處理器計算機,並且針對記憶體不足(通常是嵌入式系統)進行了優化。
  • 並行(吞吐量收集器):它並行進行次要收集,以減少垃圾收集的開銷。它是為在多處理器硬體上執行的中型到大型資料集應用程式而構建的。
  • CMS(併發標記掃描收集器):它旨在縮短垃圾收集器的暫停時間。專為具有大量長壽命物件或大量長期使用期限的應用程式而設計。CMS收集器是generational的。
  • G1(吞吐量/等待時間平衡): Garbage-First是伺服器樣式的垃圾收集器,設計用於具有大記憶體的多處理器計算機。它是一個壓縮收集器(它壓縮得足夠避免使用沒有細粒度的列表進行分配)。
  • ZGC(低延遲)

序列和並行稱為“世界停止”演算法。CMS在JDK 9中已棄用,用G1代替。

比較它們很有趣。ZGC可同時執行所有繁重的操作,而其他演算法則無法做到(更多詳細資訊請參見下文)。

 

深入Z垃圾收集器

ZGC是併發的低延遲演算法,除了執行緒堆疊掃描外,它所有併發的操作(標記,壓縮,參考處理,重定位集選擇,StringTable清理,JNI WeakRef清理,JNI GlobalRefs掃描和類解除安裝)。這使得該演算法對於低延遲確實非常有用。

值得一提的是,當前,暫停時間並不隨堆大小而增加,但是,暫停時間卻隨根集root-set大小(您的應用程式正在使用的Java執行緒數)而增加。

從演算法的角度來看,它是一個併發收集器,它在Java執行緒繼續執行的同時完成了所有繁重的工作。這是一個基於區域的收集器,這意味著將堆劃分為較小的區域,並且壓縮工作將集中在這些區域的子集上,即垃圾最多的區域。它是NUMA感知的,由於CPU有本地記憶體,因此可以減少延遲。它使用彩色指標和負載屏障,將在以下各節中詳細介紹。它是一個單一的一代收集器,它沒有以前回收機制的年輕或年老代。

 

ZGC階段

ZGC的GC週期分為三個暫停。

在第一階段(暫停標記開始)中,ZGC遍歷物件圖以將物件標記為活動或無用。此階段還包括實時資料的重新對映。

第二階段是“暫停標記結束”,在此階段完成參考預處理。在該階段還完成了類解除安裝和重定位集的選擇。

暫停重定位啟動是最後一個階段,在此階段要進行大量的壓縮堆工作。

  • 彩色的指標

它們是ZGC中的核心設計概念。該演算法使用64位物件指標中的一些未使用的位來儲存一些後設資料,從而可以查詢,標記,定位和重新對映物件。點選標題見配圖

  • 負載屏障

它是JIT在某些重要位置注入的程式碼。目的是檢查載入的物件引用是否具有不良顏色。當執行緒從堆中載入物件引用時,將執行負載屏障程式碼。

 

微調選項

如果要使用ZGC演算法,JDK15之前版本必須解鎖實驗選項:

-XX:+ UnlockExperimentalVMOptions -XX:+ UseZGC

預先從JDK 15開始,只需指定以下即可使用它:

-XX:+UseZGC

ZGC的設計易於調整。以下是特定的ZGC選項的列表:

JDK 15中Z垃圾收集器演算法 - JesúsNavarrete

為了瞭解使用的時間並瞭解有關演算法行為的一些數字,列印垃圾收集器日誌是很好的,只需在選擇ZGC來檢視簡單日誌時新增以下命令:

-XX:+UseZGC -Xmx<size> -Xlog:gc

或者,如果要列印更多資訊的垃圾收集器日誌,請執行以下操作:

-XX:+UseZGC -Xmx<size> -Xlog:gc*

現在,讓我們開始看看最有趣的調優選項。

  • 設定堆大小

ZGC中最重要的調整選項之一是設定最大堆大小(-Xmx <size>)。我們必須為應用程式找到正確的值,因為我們不想丟失記憶體,並且希望在GC執行時允許我們的應用程式有足夠的空間用於活動物件和分配。以下是使用示例:

-XX:+UseZGC -Xmx<size>

  • 設定併發GC執行緒

儘管ZGC具有自動設定此數字的試探法,但有時,根據我們的應用程式,指定併發GC執行緒數可能會很有趣。此選項確定GC將佔用多少CPU,因此您必須小心要提供的容量。

-XX:+UseZGC -Xmx<size> -XX:ConcGCThreads=<number>

  • 將未使用的記憶體返回到作業系統

與其他GC演算法不同,ZGC取消提交未使用的記憶體,將其返回給作業系統。對於可能會佔用記憶體的應用程式,這可能是必需的。如果要禁用此選項,則可以使用-XX:-ZUncommit。

-XX:+UseZGC -Xmx<size> -XX:-ZUncommit

  • 在Linux上啟用大頁面

此選項可提高效能,並且沒有缺點或副作用。唯一的問題是它需要root特權,這就是為什麼它不是預設選項,並且可能無法為您的應用程式啟用它的原因。檢視文件以正確設定此選項。它需要準備一些東西,選項如下所示:

-XX:+UseZGC -Xms16G -Xmx16G -XX:+UseLargePages

  • 在Linux上啟用透明的大頁面

不建議將這種大頁面用於對延遲敏感的應用程式,儘管它可以替代以前的調整選項。

-XX:+UseZGC -… -XX:+UseLargePages -XX:+UseTransparentHugePages

在這種情況下,我強烈建議您在應用程式中對其進行試驗,並注意峰值是否發生,如果發生峰值,也許這不是您的情況的選擇。

  • 啟用NUMA支援

如前所述,ZGC支援NUMA,這意味著預設情況下啟用此選項。這會將Java堆分配定向到NUMA本地記憶體。JVM可以自動禁用它,如果您需要顯式覆蓋行為,則可以使用選項-XX:+ UseNUMA或-XX:-UseNUMA。

-XX:+UseZGC -Xmx<size> -XX:+UseNUMA

-XX:+UseZGC -Xmx<size> -XX:-UseNUMA

 

總結

ZGC團隊的路線圖吸引了我兩件事。

首先是團隊正在努力將最大暫停時間減少到1 ms。執行緒堆疊掃描將同時進行,這也意味著暫停時間不會隨根集大小的增加而增加(JEP 376)。

其次,它們將使ZGC成為世代相傳的產品,因為大多數物件都是短命的,這將是另一個不錯的改進。

相關文章