[toc]
1. 前言
本文為了銜接公眾號(hào)中的前幾篇ZGC相關(guān)的文章,繼續(xù)探索ZGC在HBase集群中真實(shí)的GC表現(xiàn)能力,并把其與G1 GC做一個(gè)簡(jiǎn)單的對(duì)比,驗(yàn)證ZGC是否真如傳言中的那般,令人嘆為觀止。
在前幾篇文章中,我為大家分享了使用JDK15編譯HBase(和CDH HBase)的踩坑記錄和ZGC在HBase集群中的配置方法,有對(duì)ZGC感興趣的小伙伴,也可以親自動(dòng)手嘗試一下,體驗(yàn)體驗(yàn)這個(gè)來(lái)自未來(lái)的技術(shù)。
2. GC之痛
很多低延遲高可用的Java服務(wù)的系統(tǒng)可用性飽受GC停頓的困擾,例如:HBase,GC停頓是影響HBase讀寫(xiě)延時(shí)的一大元兇。GC停頓是指垃圾回收期間的STW(Stop The World),當(dāng)STW發(fā)生的時(shí)候,所有應(yīng)用線程停止活動(dòng),等待GC停頓的結(jié)束。
我們線上HBase集群的GC優(yōu)化經(jīng)歷過(guò)CMS和G1,G1 GC調(diào)優(yōu)之后,在很長(zhǎng)的一段時(shí)間之內(nèi),是可以滿足我們線上接口對(duì)HBase查詢延時(shí)的需求。但更高敏感的業(yè)務(wù)上線之后,我們的集群便立馬捉襟見(jiàn)肘,例如:我們的某些核心業(yè)務(wù)要求100ms內(nèi)返回結(jié)果,并且可用性要達(dá)到99.9%甚至99.99%,但在各種各樣因素的綜合影響之下,我們的集群一直無(wú)法滿足業(yè)務(wù)方的要求。
我們做過(guò)數(shù)據(jù)請(qǐng)求測(cè)試,持續(xù)用一個(gè)rowKey來(lái)循環(huán)請(qǐng)求HBase集群,統(tǒng)計(jì)查詢耗時(shí),一直無(wú)法滿足99.9%的查詢目標(biāo),而且,在耗時(shí)查詢發(fā)生的相同時(shí)間點(diǎn),也伴隨著GC的發(fā)生。單次GC的停頓,可能是導(dǎo)致我們?cè)谶@種查詢場(chǎng)景下,出現(xiàn)耗時(shí)查詢的最大元兇。
降低單次GC的時(shí)間和降低GC發(fā)生的頻率,可能會(huì)進(jìn)一步提升我們集群的查詢性能,出于這個(gè)目標(biāo),我們才開(kāi)始了對(duì)ZGC的探索之路。
3. CMS和G1停頓時(shí)間瓶頸
介紹ZGC之前,先簡(jiǎn)單回顧下CMS和G1的GC過(guò)程,以及停頓時(shí)間的瓶頸。CMS新生代的Young GC、G1和ZGC都基于標(biāo)記-復(fù)制算法,但算法具體實(shí)現(xiàn)的不同就導(dǎo)致了巨大的性能差異。
標(biāo)記-復(fù)制算法應(yīng)用在CMS新生代(ParNew是CMS默認(rèn)的新生代垃圾回收器)和G1垃圾回收器中。標(biāo)記-復(fù)制算法可以分為三個(gè)階段:
- 標(biāo)記階段,即從GC Roots集合開(kāi)始,標(biāo)記活躍對(duì)象;
- 轉(zhuǎn)移階段,即把活躍對(duì)象復(fù)制到新的內(nèi)存地址上;
- 重定位階段,因?yàn)檗D(zhuǎn)移導(dǎo)致對(duì)象的地址發(fā)生了變化,在重定位階段,所有指向?qū)ο笈f地址的指針都要調(diào)整到對(duì)象新的地址上。
下面以G1為例,通過(guò)G1中標(biāo)記-復(fù)制算法過(guò)程(G1的Young GC和Mixed GC均采用該算法),分析G1停頓耗時(shí)的主要瓶頸。G1垃圾回收周期如下圖所示:

G1的混合回收過(guò)程可以分為標(biāo)記階段、清理階段和復(fù)制階段。
標(biāo)記階段停頓分析
- 初始標(biāo)記階段:初始標(biāo)記階段是指從GC Roots出發(fā)標(biāo)記全部直接子節(jié)點(diǎn)的過(guò)程,該階段是STW的。由于GC Roots數(shù)量不多,通常該階段耗時(shí)非常短。
- 并發(fā)標(biāo)記階段:并發(fā)標(biāo)記階段是指從GC Roots開(kāi)始對(duì)堆中對(duì)象進(jìn)行可達(dá)性分析,找出存活對(duì)象。該階段是并發(fā)的,即應(yīng)用線程和GC線程可以同時(shí)活動(dòng)。并發(fā)標(biāo)記耗時(shí)相對(duì)長(zhǎng)很多,但因?yàn)椴皇荢TW,所以我們不太關(guān)心該階段耗時(shí)的長(zhǎng)短。
- 再標(biāo)記階段:重新標(biāo)記那些在并發(fā)標(biāo)記階段發(fā)生變化的對(duì)象。該階段是STW的。
清理階段停頓分析
- 清理階段清點(diǎn)出有存活對(duì)象的分區(qū)和沒(méi)有存活對(duì)象的分區(qū),該階段不會(huì)清理垃圾對(duì)象,也不會(huì)執(zhí)行存活對(duì)象的復(fù)制。該階段是STW的。
復(fù)制階段停頓分析
- 復(fù)制算法中的轉(zhuǎn)移階段需要分配新內(nèi)存和復(fù)制對(duì)象的成員變量。轉(zhuǎn)移階段是STW的,其中內(nèi)存分配通常耗時(shí)非常短,但對(duì)象成員變量的復(fù)制耗時(shí)有可能較長(zhǎng),這是因?yàn)閺?fù)制耗時(shí)與存活對(duì)象數(shù)量與對(duì)象復(fù)雜度成正比。對(duì)象越復(fù)雜,復(fù)制耗時(shí)越長(zhǎng)。
四個(gè)STW過(guò)程中,初始標(biāo)記因?yàn)橹粯?biāo)記GC Roots,耗時(shí)較短。再標(biāo)記因?yàn)閷?duì)象數(shù)少,耗時(shí)也較短。清理階段因?yàn)閮?nèi)存分區(qū)數(shù)量少,耗時(shí)也較短。轉(zhuǎn)移階段要處理所有存活的對(duì)象,耗時(shí)會(huì)較長(zhǎng)。因此,G1停頓時(shí)間的瓶頸主要是標(biāo)記-復(fù)制中的轉(zhuǎn)移階段STW。為什么轉(zhuǎn)移階段不能和標(biāo)記階段一樣并發(fā)執(zhí)行呢?主要是G1未能解決轉(zhuǎn)移過(guò)程中準(zhǔn)確定位對(duì)象地址的問(wèn)題。
G1的Young GC和CMS的Young GC,其標(biāo)記-復(fù)制全過(guò)程STW,不再詳細(xì)闡述,這里列舉幾篇范欣欣大神寫(xiě)的文章。
HBase最佳實(shí)踐-CMS GC調(diào)優(yōu)
4. ZGC 原理
4.1 全并發(fā)的ZGC
與CMS中的ParNew和G1類似,ZGC也采用標(biāo)記-復(fù)制算法,不過(guò)ZGC對(duì)該算法做了重大改進(jìn):ZGC在標(biāo)記、轉(zhuǎn)移和重定位階段幾乎都是并發(fā)的,這是ZGC實(shí)現(xiàn)停頓時(shí)間小于10ms目標(biāo)的最關(guān)鍵原因。
ZGC垃圾回收周期如下圖所示:

ZGC只有三個(gè)STW階段:初始標(biāo)記,再標(biāo)記,初始轉(zhuǎn)移。其中,初始標(biāo)記和初始轉(zhuǎn)移分別都只需要掃描所有GC Roots,其處理時(shí)間和GC Roots的數(shù)量成正比,一般情況耗時(shí)非常短;再標(biāo)記階段STW時(shí)間很短,最多1ms,超過(guò)1ms則再次進(jìn)入并發(fā)標(biāo)記階段。即,ZGC幾乎所有暫停都只依賴于GC Roots集合大小,停頓時(shí)間不會(huì)隨著堆的大小或者活躍對(duì)象的大小而增加。與ZGC對(duì)比,G1的轉(zhuǎn)移階段完全STW的,且停頓時(shí)間隨存活對(duì)象的大小增加而增加。
4.2 ZGC中的關(guān)鍵技術(shù)
ZGC通過(guò)著色指針和讀屏障技術(shù),解決了轉(zhuǎn)移過(guò)程中準(zhǔn)確訪問(wèn)對(duì)象的問(wèn)題,實(shí)現(xiàn)了并發(fā)轉(zhuǎn)移。大致原理描述如下:并發(fā)轉(zhuǎn)移中“并發(fā)”意味著GC線程在轉(zhuǎn)移對(duì)象的過(guò)程中,應(yīng)用線程也在不停地訪問(wèn)對(duì)象。假設(shè)對(duì)象發(fā)生轉(zhuǎn)移,但對(duì)象地址未及時(shí)更新,那么應(yīng)用線程可能訪問(wèn)到舊地址,從而造成錯(cuò)誤。而在ZGC中,應(yīng)用線程訪問(wèn)對(duì)象將觸發(fā)“讀屏障”,如果發(fā)現(xiàn)對(duì)象被移動(dòng)了,那么“讀屏障”會(huì)把讀出來(lái)的指針更新到對(duì)象的新地址上,這樣應(yīng)用線程始終訪問(wèn)的都是對(duì)象的新地址。那么,JVM是如何判斷對(duì)象被移動(dòng)過(guò)呢?就是利用對(duì)象引用的地址,即著色指針。下面介紹著色指針和讀屏障技術(shù)細(xì)節(jié)。
著色指針
|著色指針是一種將信息存儲(chǔ)在指針中的技術(shù)。
ZGC僅支持64位系統(tǒng),它把64位虛擬地址空間劃分為多個(gè)子空間,如下圖所示:

其中,[0~4TB) 對(duì)應(yīng)Java堆,[4TB ~ 8TB) 稱為M0地址空間,[8TB ~ 12TB) 稱為M1地址空間,[12TB ~ 16TB) 預(yù)留未使用,[16TB ~ 20TB) 稱為Remapped空間。
當(dāng)應(yīng)用程序創(chuàng)建對(duì)象時(shí),首先在堆空間申請(qǐng)一個(gè)虛擬地址,但該虛擬地址并不會(huì)映射到真正的物理地址。ZGC同時(shí)會(huì)為該對(duì)象在M0、M1和Remapped地址空間分別申請(qǐng)一個(gè)虛擬地址,且這三個(gè)虛擬地址對(duì)應(yīng)同一個(gè)物理地址,但這三個(gè)空間在同一時(shí)間有且只有一個(gè)空間有效。ZGC之所以設(shè)置三個(gè)虛擬地址空間,是因?yàn)樗褂谩翱臻g換時(shí)間”思想,去降低GC停頓時(shí)間?!翱臻g換時(shí)間”中的空間是虛擬空間,而不是真正的物理空間。后續(xù)章節(jié)將詳細(xì)介紹這三個(gè)空間的切換過(guò)程。
與上述地址空間劃分相對(duì)應(yīng),ZGC實(shí)際僅使用64位地址空間的第041位,而第4245位存儲(chǔ)元數(shù)據(jù),第47~63位固定為0。

ZGC將對(duì)象存活信息存儲(chǔ)在42~45位中,這與傳統(tǒng)的垃圾回收并將對(duì)象存活信息放在對(duì)象頭中完全不同。
讀屏障
| 讀屏障是JVM向應(yīng)用代碼插入一小段代碼的技術(shù)。當(dāng)應(yīng)用線程從堆中讀取對(duì)象引用時(shí),就會(huì)執(zhí)行這段代碼。需要注意的是,僅“從堆中讀取對(duì)象引用”才會(huì)觸發(fā)這段代碼。
讀屏障示例:

ZGC中讀屏障的代碼作用:在對(duì)象標(biāo)記和轉(zhuǎn)移過(guò)程中,用于確定對(duì)象的引用地址是否滿足條件,并作出相應(yīng)動(dòng)作。
ZGC并發(fā)處理演示
接下來(lái)詳細(xì)介紹ZGC一次垃圾回收周期中地址視圖的切換過(guò)程:
- 初始化:ZGC初始化之后,整個(gè)內(nèi)存空間的地址視圖被設(shè)置為Remapped。程序正常運(yùn)行,在內(nèi)存中分配對(duì)象,滿足一定條件后垃圾回收啟動(dòng),此時(shí)進(jìn)入標(biāo)記階段。
- 并發(fā)標(biāo)記階段:第一次進(jìn)入標(biāo)記階段時(shí)視圖為M0,如果對(duì)象被GC標(biāo)記線程或者應(yīng)用線程訪問(wèn)過(guò),那么就將對(duì)象的地址視圖從Remapped調(diào)整為M0。所以,在標(biāo)記階段結(jié)束之后,對(duì)象的地址要么是M0視圖,要么是Remapped。如果對(duì)象的地址是M0視圖,那么說(shuō)明對(duì)象是活躍的;如果對(duì)象的地址是Remapped視圖,說(shuō)明對(duì)象是不活躍的。
- 并發(fā)轉(zhuǎn)移階段:標(biāo)記結(jié)束后就進(jìn)入轉(zhuǎn)移階段,此時(shí)地址視圖再次被設(shè)置為Remapped。如果對(duì)象被GC轉(zhuǎn)移線程或者應(yīng)用線程訪問(wèn)過(guò),那么就將對(duì)象的地址視圖從M0調(diào)整為Remapped。
其實(shí),在標(biāo)記階段存在兩個(gè)地址視圖M0和M1,上面的過(guò)程顯示只用了一個(gè)地址視圖。之所以設(shè)計(jì)成兩個(gè),是為了區(qū)別前一次標(biāo)記和當(dāng)前標(biāo)記。即第二次進(jìn)入并發(fā)標(biāo)記階段后,地址視圖調(diào)整為M1,而非M0。
著色指針和讀屏障技術(shù)不僅應(yīng)用在并發(fā)轉(zhuǎn)移階段,還應(yīng)用在并發(fā)標(biāo)記階段:將對(duì)象設(shè)置為已標(biāo)記,傳統(tǒng)的垃圾回收器需要進(jìn)行一次內(nèi)存訪問(wèn),并將對(duì)象存活信息放在對(duì)象頭中;而在ZGC中,只需要設(shè)置指針地址的第42~45位即可,并且因?yàn)槭羌拇嫫髟L問(wèn),所以速度比訪問(wèn)內(nèi)存更快。

5. 初探ZGC在HBase中的GC表現(xiàn)
ZGC相關(guān)的調(diào)優(yōu)參數(shù)究竟該如何配置,實(shí)在無(wú)法提供出來(lái)一個(gè)標(biāo)準(zhǔn)的答案。我們參考美團(tuán)ZGC實(shí)踐中的一個(gè)案例,來(lái)針對(duì)我所用的HBase集群來(lái)進(jìn)行ZGC相關(guān)參數(shù)的設(shè)置,然后在YCSB的壓測(cè)場(chǎng)景下,收集、分析ZGC的GC日志。
參考的文章鏈接是,其中上文有關(guān)G1和ZGC的理論知識(shí)剖析也是摘選自這篇文章。
https://www.secpulse.com/archives/137305.html
新一代垃圾回收器ZGC的探索與實(shí)踐——美團(tuán)
https://www.secpulse.com/archives/137305.html
此次測(cè)試使用的HBase集群由三個(gè)節(jié)點(diǎn)組成,物理機(jī)配置:24核,內(nèi)存370G,其中為HBase分配了31G的堆內(nèi)存。HBase的版本是cdh-6.3.2-hbase2.1.0。壓測(cè)時(shí)使用的工具是阿里的AHBench(基于YCSB包裝了一層,方便對(duì)YCSB測(cè)試結(jié)果數(shù)據(jù)的收集和匯總),并保證在測(cè)試期間,唯一的變量是GC的使用方式。
YCSB壓測(cè)的場(chǎng)景是:數(shù)據(jù)量一個(gè)億,分別在使用G1和ZGC的場(chǎng)景下跑AHBench的full_test,然后對(duì)測(cè)試期間G1和ZGC的詳細(xì)gc日志生成GC指標(biāo)分析報(bào)告。
RegionServer重要配置參數(shù)示例:
-Xms31G -Xmx31G
-XX:ReservedCodeCacheSize=256m -XX:InitialCodeCacheSize=256m
-XX:+UnlockExperimentalVMOptions -XX:+UseZGC
-XX:ConcGCThreads=2 -XX:ParallelGCThreads=6
-XX:ZCollectionInterval=120 -XX:ZAllocationSpikeTolerance=5
-XX:+UnlockDiagnosticVMOptions -XX:-ZProactive
-Xlog:safepoint,classhisto*=trace,age*,gc*=info:file=/var/log/hbase/region-server-zgc-%t.log:time,tid,tags:filecount=5,filesize=500m
--illegal-access=deny
--add-exports=java.base/jdk.internal.access=ALL-UNNAMED
--add-exports=java.base/jdk.internal=ALL-UNNAMED
--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED
--add-exports=java.base/sun.security.pkcs=ALL-UNNAMED
--add-exports=java.base/sun.nio.ch=ALL-UNNAMED
--add-opens=java.base/java.nio=ALL-UNNAMED
--add-opens java.base/jdk.internal.misc=ALL-UNNAMED
-Dorg.apache.hbase.thirdparty.io.netty.tryReflectionSetAccessible=true
-Xms -Xmx:堆的最大內(nèi)存和最小內(nèi)存,這里都設(shè)置為31G,程序的堆內(nèi)存將保持31G不變。
-XX:ReservedCodeCacheSize -XX:InitialCodeCacheSize: 設(shè)置CodeCache的大小, JIT編譯的代碼都放在CodeCache中,一般服務(wù)64m或128m就已經(jīng)足夠。這里設(shè)置的數(shù)值也只是參考了美團(tuán)ZGC實(shí)踐示例。
-XX:+UnlockExperimentalVMOptions -XX:+UseZGC:?jiǎn)⒂肸GC的配置。
-XX:ConcGCThreads:并發(fā)回收垃圾的線程。默認(rèn)是總核數(shù)的12.5%,8核CPU默認(rèn)是1。調(diào)大后GC變快,但會(huì)占用程序運(yùn)行時(shí)的CPU資源,吞吐會(huì)受到影響。
這個(gè)參數(shù)的設(shè)置效果,在CDH的CPU指標(biāo)監(jiān)控圖例中就可以明顯看得到。

在ZGC測(cè)試期間,我們觀察到CPU的消耗較以往顯著增加,尤其是在集群高負(fù)載的情況下格外明顯,而其他使用G1 GC的HBase集群中的CPU負(fù)載趨勢(shì)則如下圖所示:

-XX:ParallelGCThreads:STW階段使用線程數(shù),默認(rèn)是總核數(shù)的60%。
-XX:ZCollectionInterval:ZGC發(fā)生的最小時(shí)間間隔,單位秒,該參數(shù)的設(shè)置效果在CDH中的GC時(shí)間監(jiān)控圖例中得到體現(xiàn)。

正常情況下GC發(fā)生的頻次,時(shí)間間隔均勻,正是兩分鐘(120s)。-XX:ZCollectionInterval=120。而且,在集群高負(fù)載的情況下,ZGC的GC時(shí)間可以達(dá)到分鐘級(jí)別,這也正印證了,ZGC全程并發(fā),不會(huì)影響到你的應(yīng)用進(jìn)程。因?yàn)?,如果是秒?jí)別甚至分鐘級(jí)別的STW,你的業(yè)務(wù)方早已提刀而來(lái)。G1 GC場(chǎng)景下,GC的消耗時(shí)間趨勢(shì)如下圖:

我們?cè)谶M(jìn)行G1 GC調(diào)優(yōu)設(shè)置參數(shù)的時(shí)候,期望的GC時(shí)間是在100ms,但真實(shí)的情況是不管如何調(diào)整,GC的耗時(shí)遠(yuǎn)超100ms。
200ms GC耗時(shí)均值中的STW的時(shí)間占比,將直接影響著HBase集群查詢延時(shí)的占比。
-XX:ZAllocationSpikeTolerance:ZGC觸發(fā)自適應(yīng)算法的修正系數(shù),默認(rèn)2,數(shù)值越大,越早的觸發(fā)ZGC。
-XX:+UnlockDiagnosticVMOptions -XX:-ZProactive:是否啟用主動(dòng)回收,默認(rèn)開(kāi)啟,這里的配置表示關(guān)閉。
-Xlog:設(shè)置GC日志中的內(nèi)容、格式、位置以及每個(gè)日志的大小。
理解ZGC的觸發(fā)時(shí)機(jī)
相比于CMS和G1的GC觸發(fā)機(jī)制,ZGC的GC觸發(fā)機(jī)制有很大不同。ZGC的核心特點(diǎn)是并發(fā),GC過(guò)程中一直有新的對(duì)象產(chǎn)生。如何保證在GC完成之前,新產(chǎn)生的對(duì)象不會(huì)將堆占滿,是ZGC參數(shù)調(diào)優(yōu)的第一大目標(biāo)。因?yàn)樵赯GC中,當(dāng)垃圾來(lái)不及回收將堆占滿時(shí),會(huì)導(dǎo)致正在運(yùn)行的線程停頓,持續(xù)時(shí)間可能長(zhǎng)達(dá)秒級(jí)之久。
ZGC有多種GC觸發(fā)機(jī)制,總結(jié)如下:
- 阻塞內(nèi)存分配請(qǐng)求觸發(fā):當(dāng)垃圾來(lái)不及回收,垃圾將堆占滿時(shí),會(huì)導(dǎo)致部分線程阻塞。我們應(yīng)當(dāng)避免出現(xiàn)這種觸發(fā)方式。日志中關(guān)鍵字是“Allocation Stall”。
- 基于分配速率的自適應(yīng)算法:最主要的GC觸發(fā)方式,其算法原理可簡(jiǎn)單描述為”ZGC根據(jù)近期的對(duì)象分配速率以及GC時(shí)間,計(jì)算出當(dāng)內(nèi)存占用達(dá)到什么閾值時(shí)觸發(fā)下一次GC”。自適應(yīng)算法的詳細(xì)理論可參考彭成寒《新一代垃圾回收器ZGC設(shè)計(jì)與實(shí)現(xiàn)》一書(shū)中的內(nèi)容。通過(guò)ZAllocationSpikeTolerance參數(shù)控制閾值大小,該參數(shù)默認(rèn)2,數(shù)值越大,越早的觸發(fā)GC。我們通過(guò)調(diào)整此參數(shù)解決了一些問(wèn)題。日志中關(guān)鍵字是“Allocation Rate”。
- 基于固定時(shí)間間隔:通過(guò)ZCollectionInterval控制,適合應(yīng)對(duì)突增流量場(chǎng)景。流量平穩(wěn)變化時(shí),自適應(yīng)算法可能在堆使用率達(dá)到95%以上才觸發(fā)GC。流量突增時(shí),自適應(yīng)算法觸發(fā)的時(shí)機(jī)可能會(huì)過(guò)晚,導(dǎo)致部分線程阻塞。我們通過(guò)調(diào)整此參數(shù)解決流量突增場(chǎng)景的問(wèn)題,比如定時(shí)活動(dòng)、秒殺等場(chǎng)景。日志中關(guān)鍵字是“Timer”。
- 主動(dòng)觸發(fā)規(guī)則:類似于固定間隔規(guī)則,但時(shí)間間隔不固定,是ZGC自行算出來(lái)的時(shí)機(jī),我們的服務(wù)因?yàn)橐呀?jīng)加了基于固定時(shí)間間隔的觸發(fā)機(jī)制,所以通過(guò)-ZProactive參數(shù)將該功能關(guān)閉,以免GC頻繁,影響服務(wù)可用性。日志中關(guān)鍵字是“Proactive”。
- 預(yù)熱規(guī)則:服務(wù)剛啟動(dòng)時(shí)出現(xiàn),一般不需要關(guān)注。日志中關(guān)鍵字是“Warmup”。
- 外部觸發(fā):代碼中顯式調(diào)用System.gc()觸發(fā)。日志中關(guān)鍵字是“System.gc()”。
- 元數(shù)據(jù)分配觸發(fā):元數(shù)據(jù)區(qū)不足時(shí)導(dǎo)致,一般不需要關(guān)注。日志中關(guān)鍵字是“Metadata GC Threshold”。
更細(xì)致的GC 日志分析,可以參考美團(tuán)ZGC實(shí)踐那篇文章中的分析思路。
6. ZGC與G1 GC的數(shù)據(jù)統(tǒng)計(jì)對(duì)比
我們收集ZGC與G1 GC在相同壓測(cè)場(chǎng)景下生成的詳細(xì)gc日志,上傳到https://gceasy.io/之后,分別得出的GC報(bào)告如下圖所示:
6.1 G1

6.2 ZGC

僅從這兩個(gè)GC報(bào)告對(duì)比來(lái)看,ZGC確實(shí)做到了幾乎百分之百的GC時(shí)間在10ms內(nèi)。
6.3 G1與ZGC吞吐量相關(guān)指標(biāo)比較
以下圖例記錄了相同YCSB壓測(cè)場(chǎng)景下,G1與ZGC各項(xiàng)指標(biāo)比較。
讀寫(xiě)吞吐量指標(biāo)比較

讀寫(xiě)平均延時(shí)指標(biāo)比較

G1與ZGCp999延時(shí)指標(biāo)比較

以上指標(biāo)對(duì)比,在不同的壓測(cè)場(chǎng)景,不同的集群環(huán)境之下的結(jié)果可能會(huì)有所不同,不能代表線上真正的表現(xiàn)情況,希望大家如感興趣,可以親自嘗試測(cè)試一波。
7. 總結(jié)
本篇文章為大家分享了ZGC的特點(diǎn),簡(jiǎn)單記錄了ZGC的一些核心技術(shù),如著色指針、讀屏障等。并在相同的YCSB壓測(cè)場(chǎng)景下,分別測(cè)試了G1和ZGC在真實(shí)的應(yīng)用環(huán)境中的GC的表現(xiàn)能力,并得出GC分析報(bào)告,從GC停頓時(shí)間和讀寫(xiě)吞吐、延遲等方面,做了比較詳細(xì)的對(duì)比,然后初步驗(yàn)證了以下幾個(gè)觀點(diǎn):
- ZGC 可以達(dá)到幾乎百分百GC耗時(shí)在10ms內(nèi)的目標(biāo)
- 通過(guò)設(shè)置參數(shù),可以主動(dòng)控制ZGC的GC發(fā)生頻率
- 與G1相比,ZGC在GC過(guò)程中會(huì)消耗更多的CPU
有關(guān)GC更深入的理解和使用,甚至進(jìn)一步調(diào)優(yōu)ZGC的表現(xiàn)能力,這將在后續(xù)的文章中繼續(xù)和大家探討。同時(shí),本人對(duì)GC的認(rèn)知有限,文中個(gè)別地方描述不恰當(dāng),或?qū)?shí)驗(yàn)數(shù)據(jù)心存異議的伙伴,還請(qǐng)及時(shí)告知。
8. 參考鏈接
https://www.secpulse.com/archives/137305.html
http://hbasefly.com/2016/05/21/hbase-gc-1/