<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垃圾收集器

          共 4618字,需瀏覽 10分鐘

           ·

          2021-01-14 14:27


          南京 | 攝影?萬里


          ZGC介紹



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

          • 停頓時間不超過10ms;

          • 停頓時間不會隨著堆的大小,或者活躍對象的大小而增加;

          • 支持8MB~4TB級別的堆,未來支持16TB。

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


          ZGC以追求低停頓為主要目標,STW的時候能控制在10ms以內(nèi)。本文會從ZGC的設計思路出發(fā),講清楚為何ZGC能在低延時場景中的應用中有著如此卓越的表現(xiàn)。


          多重映射


          ZGC參照操作系統(tǒng)中的虛擬地址和物理地址,設計了一套內(nèi)存和地址的多重映射關系。


          為了能更好的理解ZGC的多重映射,我們先看一下這個例子:


          你在你爸爸媽媽眼中是兒子,在你女朋友眼中是男朋友。在全世界人面前就是最帥的人。你還有一個名字,但名字也只是你的一個代號,并不是你本人。


          將這個關系畫一張映射圖表示:



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


          現(xiàn)在我們再來看看ZGC的內(nèi)存映射。


          ZGC為了能高效、靈活地管理內(nèi)存,實現(xiàn)了兩級內(nèi)存管理:虛擬內(nèi)存和物理內(nèi)存,并且實現(xiàn)了物理內(nèi)存和虛擬內(nèi)存的映射關系。


          當應用程序創(chuàng)建對象時,首先在堆空間申請一個虛擬地址,ZGC同時會為該對象在Marked0、Marked1和Remapped三個視圖空間分別申請一個虛擬地址,且這三個虛擬地址對應同一個物理地址。




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


          這是ZGC的三個視圖空間,在ZGC中這三個空間在同一時間點有且僅有一個空間有效。


          對照上面的例子,這三個視圖分別對應的就是"你爸爸眼中",“你女朋友的眼中”,“全世界人眼中”。


          而三個視圖里面的地址,都是虛擬地址。對應的是“你爸爸眼中的兒子”,“你女朋友眼中的男朋友”......


          最后,這些虛地址都能映射到同一個物理地址,這個物理地址對應上面例子中的“你本人”。


          用一段簡單的Java代碼表示這種關系:




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


          染色指針

          染色指針是一種將信息存儲在指針中的技術(shù)。

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


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


          而ZGC是這樣做的:


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


          在這例子中,“這個人”就是一個對象,而“身份證”就是指向這個對象的指針。這種指針有一個高大上的名字——染色指針(Colored Pointer)。



          在64位的機器中,對象指針是64位的。

          • ZGC使用64位地址空間的第0~43位存儲對象地址,2^44 = 16TB,所以ZGC最大支持16TB的堆。

          • 而第44~47位作為顏色標志位,Marked0、Marked1和Remapped分別對應三個視圖空間。????????????????????????????????

          • 第48~63位固定為0暫時沒有使用。



          讀屏障



          讀屏障是JVM向應用代碼插入一小段代碼的技術(shù)。


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


          讀屏障實例:



          ZGC中讀屏障的代碼作用:


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


          具體的探測和操作步驟如下:




          這樣會影響程序的性能嗎?


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


          ZGC并發(fā)處理算法


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


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


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

          • 初始化階段:ZGC初始化之后,整個內(nèi)存空間的地址視圖被設置為Remapped
          • 標記階段:當進入標記階段時的視圖轉(zhuǎn)變?yōu)镸arked0(以下皆簡稱M0)或者Marked1(以下皆簡稱M1)

          • 轉(zhuǎn)移階段:從標記階段結(jié)束進入轉(zhuǎn)移階段時的視圖再次設置為Remapped





          標記階段


          標記階段全局視圖切換到M0視圖。因為應用程序和標記線程并發(fā)執(zhí)行,那么對象的訪問可能來自標記線程和應用程序線程。




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

          • 如果對象的地址視圖是M0,說明對象是活躍的;

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

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




          轉(zhuǎn)移階段


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



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


          為何要設計M0和M1


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


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


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

          • M1:本次垃圾回收中識別的活躍對象。

          • M0:前一次垃圾回收的標記階段被標記過的活躍對象,對象在轉(zhuǎn)移階段未被轉(zhuǎn)移,但是在本次垃圾回收中被識別為不活躍對象。

          • Remapped:前一次垃圾回收的轉(zhuǎn)移階段發(fā)生轉(zhuǎn)移的對象或者是被應用程序線程訪問的對象,但是在本次垃圾回收中被識別為不活躍對象。

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


          使用地址視圖和染色指針可以加快標記和轉(zhuǎn)移的速度。


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


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




          ZGC垃圾回收周期



          ZGC采用的是標記-復制算法,標記、轉(zhuǎn)移和重定位階段幾乎都是并發(fā)的,ZGC垃圾回收周期如下圖所示:




          ZGC只有三個STW階段:初始標記再標記初始轉(zhuǎn)移


          其中,初始標記和初始轉(zhuǎn)移分別都只需要掃描所有GC Roots,其處理時間和GC Roots的數(shù)量成正比,一般情況耗時非常短;


          再標記階段STW時間很短,最多1ms,超過1ms則再次進入并發(fā)標記階段。即ZGC幾乎所有暫停都只依賴于GC Roots集合大小,停頓時間不會隨著堆的大小或者活躍對象的大小而增加。




          ZGC的發(fā)展



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


          從只支持Linux/x64,到現(xiàn)在支持多平臺;從不支持指針壓縮,到支持壓縮類指針.....ZGC迭代的速度非常快。




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


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


          ZGC卓越的表現(xiàn),讓我們開發(fā)者看到了商用級別的GC“飛入尋常百姓家”的希望,隨著JDK的發(fā)展,我相信在未來的某一天,JVM調(diào)優(yōu)這種反人類的操作將不復存在,底層的GC會自適應各種情況自動優(yōu)化。




          總結(jié)



          ZGC是Java的最前沿的技術(shù)的代表。


          ZGC追求低停頓時間,并將此做到極致,雖然犧牲了一部分的性能,但完全可以接受。其中的染色指針技術(shù)和多重映射思想也值得我們學習。


          ZGC多個視圖之間的切換,某個瞬間,我看到了電影《信條》的影子。


          在G1都沒有普及的今天,談論ZGC似乎為時過早。但不管怎么樣,ZGC都是一款優(yōu)秀的垃圾收集器,值得我們?nèi)W習。


          [1] 參考文章

          : https://mp.weixin.qq.com/s/ag5u2EPObx7bZr7hkcrOTg

          [2] 參考文章

          : https://wiki.openjdk.java.net/display/zgc/Main

          [3] 參考文章

          :?https://www.usenix.org/legacy/events/vee05/full_papers/p46-click.pdf

          [4] 參考書籍:《新一代垃圾回收器ZGC設計與實現(xiàn)》



          —————END—————


          推薦閱讀:



          最近面試BAT,整理一份面試資料Java面試BAT通關手冊,覆蓋了Java核心技術(shù)、JVM、Java并發(fā)、SSM、微服務、數(shù)據(jù)庫、數(shù)據(jù)結(jié)構(gòu)等等。

          獲取方式:點“在看”,關注公眾號并回復?666?領取,更多內(nèi)容陸續(xù)奉上。

          明天見(??ω??)??
          瀏覽 41
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <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>
                  亚州男人的天堂 | 九哥艹逼网 | 日本骚虎网站 | 日韩成人综合 | 淫色一非一区二区朝鲜 |