<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Java最前沿技術(shù)——ZGC

          共 4378字,需瀏覽 9分鐘

           ·

          2021-01-19 07:47

          作者:CoderW
          來源:SegmentFault 思否社區(qū)



          ZGC介紹


          ZGC(The Z Garbage Collector)是JDK 11中推出的一款追求極致低延遲的實(shí)驗(yàn)性質(zhì)的垃圾收集器,它曾經(jīng)設(shè)計(jì)目標(biāo)包括:


          • 停頓時(shí)間不超過10ms;
          • 停頓時(shí)間不會(huì)隨著堆的大小,或者活躍對(duì)象的大小而增加;
          • 支持8MB~4TB級(jí)別的堆(未來支持16TB)。

          當(dāng)初,提出這個(gè)目標(biāo)的時(shí)候,有很多人都覺得設(shè)計(jì)者在吹牛逼。

          但今天看來,這些“吹下的牛逼”都在一個(gè)個(gè)被實(shí)現(xiàn)。

          基于最新的JDK15來看,“停頓時(shí)間不超過10ms”和“支持16TB的堆”這兩個(gè)目標(biāo)已經(jīng)實(shí)現(xiàn),并且官方明確指出JDK15中的ZGC不再是實(shí)驗(yàn)性質(zhì)的垃圾收集器,且建議投入生產(chǎn)了。

          ZGC已經(jīng)熟了,面試題還會(huì)遠(yuǎn)嗎?

          本文會(huì)從ZGC的設(shè)計(jì)思路出發(fā),講清楚為何ZGC能在低延時(shí)場景中的應(yīng)用中有著如此卓越的表現(xiàn)。



          核心技術(shù)


          多重映射


          為了能更好的理解ZGC的內(nèi)存管理,我們先看一下這個(gè)例子:

          你在你爸爸媽媽眼中是兒子,在你女朋友眼中是男朋友。在全世界人面前就是最帥的人。你還有一個(gè)名字,但名字也只是你的一個(gè)代號(hào),并不是你本人。將這個(gè)關(guān)系畫一張映射圖表示:


          • 在你爸爸的眼中,你就是兒子;
          • 在你女朋友的眼中,你就說男朋友;
          • 站在全世界角度來看,你就說世界上最帥的人;

          假如你的名字是全世界唯一的,通過“你的名字”、“你爸爸的兒子”、“你女朋友的男朋友”,“世界上最帥的人”最后定位到的都是你本人。

          現(xiàn)在我們?cè)賮砜纯碯GC的內(nèi)存管理。

          ZGC為了能高效、靈活地管理內(nèi)存,實(shí)現(xiàn)了兩級(jí)內(nèi)存管理:虛擬內(nèi)存和物理內(nèi)存,并且實(shí)現(xiàn)了物理內(nèi)存和虛擬內(nèi)存的映射關(guān)系。這和操作系統(tǒng)中虛擬地址和物理地址設(shè)計(jì)思路基本一致。

          當(dāng)應(yīng)用程序創(chuàng)建對(duì)象時(shí),首先在堆空間申請(qǐng)一個(gè)虛擬地址,ZGC同時(shí)會(huì)為該對(duì)象在Marked0、Marked1和Remapped三個(gè)視圖空間分別申請(qǐng)一個(gè)虛擬地址,且這三個(gè)虛擬地址對(duì)應(yīng)同一個(gè)物理地址。


          圖中的Marked0、Marked1和Remapped三個(gè)視圖是什么意思呢?

          對(duì)照上面的例子,這三個(gè)視圖分別對(duì)應(yīng)的就是"你爸爸眼中",“你女朋友的眼中”,“全世界人眼中”。

          而三個(gè)視圖里面的地址,都是虛擬地址,對(duì)應(yīng)的是“你爸爸眼中的兒子”,“你女朋友眼中的男朋友”......

          最后,這些虛地址都能映射到同一個(gè)物理地址,這個(gè)物理地址對(duì)應(yīng)上面例子中的“你本人”。

          用一段簡單的Java代碼表示這種關(guān)系:


          在ZGC中這三個(gè)空間在同一時(shí)間點(diǎn)有且僅有一個(gè)空間有效。

          為什么這么設(shè)計(jì)呢?這就是ZGC的高明之處,利用虛擬空間換時(shí)間,這三個(gè)空間的切換是由垃圾回收的不同階段觸發(fā)的,通過限定三個(gè)空間在同一時(shí)間點(diǎn)有且僅有一個(gè)空間有效高效的完成GC過程的并發(fā)操作,具體實(shí)現(xiàn)會(huì)在后面講ZGC并發(fā)處理算法的部分再詳細(xì)描述。

          染色指針


          在講ZGC并發(fā)處理算法之前,還需要補(bǔ)充一個(gè)知識(shí)點(diǎn)——染色指針。

          我們都知道,之前的垃圾收集器都是把GC信息(標(biāo)記信息、GC分代年齡..)存在對(duì)象頭的Mark Word里。舉個(gè)例子:

          如果某個(gè)人是個(gè)垃圾人,就在這個(gè)人的頭上蓋一個(gè)“垃圾”的章;如果這個(gè)人不是垃圾了,就把這個(gè)人頭上的“垃圾”印章洗掉。

          而ZGC是這樣做的:

          如果某個(gè)人是垃圾人。就在這個(gè)人的身份證信息里面標(biāo)注這個(gè)人是個(gè)垃圾,以后不管這個(gè)人在哪刷身份證,別人都知道他是個(gè)垃圾人了。也許哪一天,這個(gè)人醒悟了不再是垃圾人了,就把這個(gè)人身份證里面的“垃圾”標(biāo)志去掉。

          在這例子中,“這個(gè)人”就是一個(gè)對(duì)象,而“身份證”就是指向這個(gè)對(duì)象的指針。

          ZGC將信息存儲(chǔ)在指針中,這種技術(shù)有一個(gè)高大上的名字——染色指針(Colored Pointer)。


          在64位的機(jī)器中,對(duì)象指針是64位的。

          • ZGC使用64位地址空間的第0~43位存儲(chǔ)對(duì)象地址,2^44 = 16TB,所以ZGC最大支持16TB的堆。
          • 而第44~47位作為顏色標(biāo)志位,Marked0、Marked1和Remapped代表三個(gè)視圖標(biāo)志位,F(xiàn)inalizable表示這個(gè)對(duì)象只能通過finalizer才能訪問。
          • 第48~63位固定為0沒有利用。


          讀屏障


          讀屏障是JVM向應(yīng)用代碼插入一小段代碼的技術(shù)。當(dāng)應(yīng)用線程從堆中讀取對(duì)象引用時(shí),就會(huì)執(zhí)行這段代碼。千萬不要把這個(gè)讀屏障和Java內(nèi)存模型里面的讀屏障搞混了,兩者根本不是同一個(gè)東西,ZGC中的讀屏障更像是一種AOP技術(shù),在字節(jié)碼層面或者編譯代碼層面給讀操作增加一個(gè)額外的處理。

          讀屏障實(shí)例:

          Object?o?=?obj.FieldA??????//?從堆中讀取對(duì)象引用,需要加入讀屏障

          ??
          Object?p?=?o???????????????//?無需加入讀屏障,因?yàn)椴皇菑亩阎凶x取引用
          o.dosomething()????????????//?無需加入讀屏障,因?yàn)椴皇菑亩阎凶x取引用
          int?i?=??obj.FieldB????????//?無需加入讀屏障,因?yàn)椴皇菍?duì)象引用

          ZGC中讀屏障的代碼作用:

          GC線程和應(yīng)用線程是并發(fā)執(zhí)行的,所以存在應(yīng)用線程去A對(duì)象內(nèi)部的引用所指向的對(duì)象B的時(shí)候,這個(gè)對(duì)象B正在被GC線程移動(dòng)或者其他操作,加上讀屏障之后,應(yīng)用線程會(huì)去探測對(duì)象B是否被GC線程操作,然后等待操作完成再讀取對(duì)象,確保數(shù)據(jù)的準(zhǔn)確性。具體的探測和操作步驟如下:


          這樣會(huì)影響程序的性能嗎?

          會(huì)。據(jù)測試,最多百分之4的性能損耗。但這是ZGC并發(fā)轉(zhuǎn)移的基礎(chǔ),為了降低STW,設(shè)計(jì)者認(rèn)為這點(diǎn)犧牲是可接受的。



          ZGC并發(fā)處理算法


          ZGC并發(fā)處理算法利用全局空間視圖的切換和對(duì)象地址視圖的切換,結(jié)合SATB算法實(shí)現(xiàn)了高效的并發(fā)。

          以上所有的鋪墊,都是為了講清楚ZGC的并發(fā)處理算法,在一些博文上,都說染色指針和讀屏障是ZGC的核心,但都沒有講清楚兩者是如何在算法里面被利用的,我認(rèn)為,ZGC的并發(fā)處理算法才是ZGC的核心,染色指針和讀屏障只不過是為算法服務(wù)而已。

          ZGC的并發(fā)處理算法三個(gè)階段的全局視圖切換如下:

          • 初始化階段:ZGC初始化之后,整個(gè)內(nèi)存空間的地址視圖被設(shè)置為Remapped
          • 標(biāo)記階段:當(dāng)進(jìn)入標(biāo)記階段時(shí)的視圖轉(zhuǎn)變?yōu)镸arked0(以下皆簡稱M0)或者M(jìn)arked1(以下皆簡稱M1)
          • 轉(zhuǎn)移階段:從標(biāo)記階段結(jié)束進(jìn)入轉(zhuǎn)移階段時(shí)的視圖再次設(shè)置為Remapped


          標(biāo)記階段


          標(biāo)記階段全局視圖切換到M0視圖。因?yàn)閼?yīng)用程序和標(biāo)記線程并發(fā)執(zhí)行,那么對(duì)象的訪問可能來自標(biāo)記線程和應(yīng)用程序線程。


          在標(biāo)記階段結(jié)束之后,對(duì)象的地址視圖要么是M0,要么是Remapped。

          • 如果對(duì)象的地址視圖是M0,說明對(duì)象是活躍的;
          • 如果對(duì)象的地址視圖是Remapped,說明對(duì)象是不活躍的,即對(duì)象所使用的內(nèi)存可以被回收。

          當(dāng)標(biāo)記階段結(jié)束后,ZGC會(huì)把所有活躍對(duì)象的地址存到對(duì)象活躍信息表,活躍對(duì)象的地址視圖都是M0。


          轉(zhuǎn)移階段


          轉(zhuǎn)移階段切換到Remapped視圖。因?yàn)閼?yīng)用程序和轉(zhuǎn)移線程也是并發(fā)執(zhí)行,那么對(duì)象的訪問可能來自轉(zhuǎn)移線程和應(yīng)用程序線程。


          至此,ZGC的一個(gè)垃圾回收周期中,并發(fā)標(biāo)記和并發(fā)轉(zhuǎn)移就結(jié)束了。

          為何要設(shè)計(jì)M0和M1


          我們提到在標(biāo)記階段存在兩個(gè)地址視圖M0和M1,上面的算法過程顯示只用到了一個(gè)地址視圖,為什么設(shè)計(jì)成兩個(gè)?簡單地說是為了區(qū)別前一次標(biāo)記和當(dāng)前標(biāo)記。

          ZGC是按照頁面進(jìn)行部分內(nèi)存垃圾回收的,也就是說當(dāng)對(duì)象所在的頁面需要回收時(shí),頁面里面的對(duì)象需要被轉(zhuǎn)移,如果頁面不需要轉(zhuǎn)移,頁面里面的對(duì)象也就不需要轉(zhuǎn)移。


          如圖,這個(gè)對(duì)象在第二次GC周期開始的時(shí)候,地址視圖還是M0。如果第二次GC的標(biāo)記階段還切到M0視圖的話,就不能區(qū)分出對(duì)象是活躍的,還是上一次垃圾回收標(biāo)記過的。這個(gè)時(shí)候,第二次GC周期的標(biāo)記階段切到M1視圖的話就可以區(qū)分了,此時(shí)這3個(gè)地址視圖代表的含義是:

          • M1:本次垃圾回收中識(shí)別的活躍對(duì)象。
          • M0:前一次垃圾回收的標(biāo)記階段被標(biāo)記過的活躍對(duì)象,對(duì)象在轉(zhuǎn)移階段未被轉(zhuǎn)移,但是在本次垃圾回收中被識(shí)別為不活躍對(duì)象。
          • Remapped:前一次垃圾回收的轉(zhuǎn)移階段發(fā)生轉(zhuǎn)移的對(duì)象或者是被應(yīng)用程序線程訪問的對(duì)象,但是在本次垃圾回收中被識(shí)別為不活躍對(duì)象。

          現(xiàn)在,我們可以回答“使用地址視圖和染色指針有什么好處”這個(gè)問題了

          使用地址視圖和染色指針可以加快標(biāo)記和轉(zhuǎn)移的速度。以前的垃圾回收器通過修改對(duì)象頭的標(biāo)記位來標(biāo)記GC信息,這是有內(nèi)存存取訪問的,而ZGC通過地址視圖和染色指針技術(shù),無需任何對(duì)象訪問,只需要設(shè)置地址中對(duì)應(yīng)的標(biāo)志位即可。這就是ZGC在標(biāo)記和轉(zhuǎn)移階段速度更快的原因。

          當(dāng)GC信息不再存儲(chǔ)在對(duì)象頭上時(shí)而存在引用指針上時(shí),當(dāng)確定一個(gè)對(duì)象已經(jīng)無用的時(shí)候,可以立即重用對(duì)應(yīng)的內(nèi)存空間,這是把GC信息放到對(duì)象頭所做不到的。



          ZGC步驟


          ZGC采用的是標(biāo)記-復(fù)制算法,標(biāo)記、轉(zhuǎn)移和重定位階段幾乎都是并發(fā)的,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,超過1ms則再次進(jìn)入并發(fā)標(biāo)記階段。即,ZGC幾乎所有暫停都只依賴于GC Roots集合大小,停頓時(shí)間不會(huì)隨著堆的大小或者活躍對(duì)象的大小而增加。與ZGC對(duì)比,G1的轉(zhuǎn)移階段完全STW的,且停頓時(shí)間隨存活對(duì)象的大小增加而增加。



          ZGC的發(fā)展


          ZGC誕生于JDK11,經(jīng)過不斷的完善,JDK15中的ZGC已經(jīng)不再是實(shí)驗(yàn)性質(zhì)的了。

          從只支持Linux/x64,到現(xiàn)在支持多平臺(tái);從不支持指針壓縮,到支持壓縮類指針.....


          在JDK16,ZGC將支持并發(fā)線程棧掃描(Concurrent Thread Stack Scanning),根據(jù)SPECjbb2015測試結(jié)果,實(shí)現(xiàn)并發(fā)線程棧掃描之后,ZGC的STW時(shí)間又能降低一個(gè)數(shù)量級(jí),停頓時(shí)間將進(jìn)入毫秒時(shí)代。


          ZGC已然是一款優(yōu)秀的垃圾收集器了,它借鑒了Pauseless GC,也似乎在朝著C4 GC的方向發(fā)展——引入分代思想。

          Oracle的努力,讓我們開發(fā)者看到了商用級(jí)別的GC“飛入尋常百姓家”的希望,隨著JDK的發(fā)展,我相信在未來的某一天,JVM調(diào)優(yōu)這種反人類的操作將不復(fù)存在,底層的GC會(huì)自適應(yīng)各種情況自動(dòng)優(yōu)化。

          ZGC確實(shí)是Java的最前沿的技術(shù),但在G1都沒有普及的今天,談?wù)揨GC似乎為時(shí)過早。但也許我們探討的不是ZGC,而是ZGC背后的設(shè)計(jì)思路。

          希望你能有所收獲!



          點(diǎn)擊左下角閱讀原文,到?SegmentFault 思否社區(qū)?和文章作者展開更多互動(dòng)和交流。

          -?END -

          瀏覽 67
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚州精品天堂中文字幕 | 99热这里只有精品9 | 成人午夜A片免费看 | 国产乱来╳╳A片视频 | 天天干天天舔天天操 |