溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

如何理解內(nèi)存布局及GC原理

發(fā)布時間:2021-10-14 15:27:33 來源:億速云 閱讀:116 作者:iii 欄目:編程語言

這篇文章主要介紹“如何理解內(nèi)存布局及GC原理”,在日常操作中,相信很多人在如何理解內(nèi)存布局及GC原理問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”如何理解內(nèi)存布局及GC原理”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!

ZGC (截止目前史上最好的 GC 收集器)

ZGC(The Z Garbage Collector) 是 JDK 11 中推出的一款低延遲垃圾回收器,它的設(shè)計(jì)目標(biāo)包括: 在G1的基礎(chǔ)上,做了很多改進(jìn)(JDK 11 開始引入)

  • 停頓時間不超過 10ms;

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

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


從設(shè)計(jì)目標(biāo)來看,我們知道 ZGC 適用于大內(nèi)存低延遲服務(wù)的內(nèi)存管理和回收。本文主要介紹 ZGC 在低延時場景中的應(yīng)用和卓越表現(xiàn),文章內(nèi)容主要分為四部分:


  • GC 之痛 :介紹實(shí)際業(yè)務(wù)中遇到的 GC 痛點(diǎn),并分析 CMS 收集器和 G1 收集器停頓時間瓶頸;

  • ZGC 原理 :分析 ZGC 停頓時間比 G1 或 CMS 更短的本質(zhì)原因,以及背后的技術(shù)原理;

  • ZGC 調(diào)優(yōu)實(shí)踐 :重點(diǎn)分享對 ZGC 調(diào)優(yōu)的理解,并分析若干個實(shí)際調(diào)優(yōu)案例;

  • 升級 ZGC 效果 :展示在生產(chǎn)環(huán)境應(yīng)用 ZGC 取得的效果。


GC 之痛

很多低延遲高可用Java服務(wù)的系統(tǒng)可用性經(jīng)常受 GC 停頓的困擾。GC 停頓指垃圾回收期間 STW(Stop The World),當(dāng) STW 時,所有應(yīng)用線程停止活動,等待GC停頓結(jié)束。


以美團(tuán)風(fēng)控服務(wù)為例,部分上游業(yè)務(wù)要求風(fēng)控服務(wù) 65ms 內(nèi)返回結(jié)果,并且可用性要達(dá)到 99.99%。但因?yàn)?GC 停頓,我們未能達(dá)到上述可用性目標(biāo)。當(dāng)時使用的是 CMS 垃圾回收器,單次 Young GC 40ms,一分鐘 10 次,接口平均響應(yīng)時間 30ms。通過計(jì)算可知,有( 40ms + 30ms ) * 10 次 / 60000ms = 1.12%的請求的響應(yīng)時間會增加 0 ~ 40ms 不等,其中 30ms * 10 次 / 60000ms = 0.5%的請求響應(yīng)時間會增加 40ms。

可見,GC 停頓對響應(yīng)時間的影響較大。為了降低 GC 停頓對系統(tǒng)可用性的影響,我們從降低單次 GC 時間和降低 GC 頻率兩個角度出發(fā)進(jìn)行了調(diào)優(yōu),還測試過G1垃圾回收器,但這三項(xiàng)措施均未能降低 GC 對服務(wù)可用性的影響。

CMS 與 G1 停頓時間瓶頸


介紹ZGC之前,首先回顧一下 CMS 和 G1 的 GC 過程以及停頓時間的瓶頸。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ù)制算法可以分為四個階段:


  1. 標(biāo)記階段,即從 GC Roots 集合開始,標(biāo)記活躍對象;

  2. 清理階段,即清理所有不活躍的對象

  3. 轉(zhuǎn)移階段,即把活躍對象復(fù)制到新的內(nèi)存地址上;

  4. 重定位階段,因?yàn)檗D(zhuǎn)移導(dǎo)致對象的地址發(fā)生了變化,在重定位階段,所有指向?qū)ο笈f地址的指針都要調(diào)整到對象新的地址上


下面以 G1 為例,通過 G1 中標(biāo)記-復(fù)制算法過程(G1 的 Young GC 和 Mixed GC 均采用該算法),分析 G1 停頓耗時的主要瓶頸。G1 垃圾回收周期如下圖所示:

如何理解內(nèi)存布局及GC原理

G1 的混合回收過程可以分為標(biāo)記階段、清理階段和復(fù)制階段。
標(biāo)記階段停頓分析
初始標(biāo)記階段 :
初始標(biāo)記階段是指從 GC Roots 出發(fā)標(biāo)記全部直接子節(jié)點(diǎn)的過程,該階段是 STW 的。由于 GC Roots 數(shù)量不多,通常該階段耗時非常短。
并發(fā)標(biāo)記階段 :
并發(fā)標(biāo)記階段是指從 GC Roots 開始對堆中對象進(jìn)行可達(dá)性分析,找出存活對象。該階段是并發(fā)的,即應(yīng)用線程和 GC 線程可以同時活動。
并發(fā)標(biāo)記耗時相對長很多,但因?yàn)椴皇?nbsp;STW,所以我們不太關(guān)心該階段耗時的長短。
再標(biāo)記階段 :
重新標(biāo)記那些在并發(fā)標(biāo)記階段發(fā)生變化的對象。該階段是 STW 的。
清理階段停頓分析
清理階段清點(diǎn)出有存活對象的分區(qū)和沒有存活對象的分區(qū),該階段不會清理垃圾對象,也不會執(zhí)行存活對象的復(fù)制。該階段是 STW 的,因此此階段不會出現(xiàn)浮動對象。
復(fù)制階段停頓分析
復(fù)制算法中的轉(zhuǎn)移階段需要分配新內(nèi)存和復(fù)制對象的成員變量。轉(zhuǎn)移階段是 STW 的,其中內(nèi)存分配通常耗時非常短,但對象成員變量的復(fù)制耗時有可能較長,這是因?yàn)閺?fù)制耗時與存活對象數(shù)量與對象復(fù)雜度成正比。對象越復(fù)雜,復(fù)制耗時越長。(不會存在內(nèi)存碎片且不適合大對象的賦值遷移)

四個 STW 過程中:
  • 初始標(biāo)記因?yàn)橹粯?biāo)記 GC Roots,耗時較短。(STW)

  • 再標(biāo)記因?yàn)閷ο髷?shù)少,耗時也較短。

  • 清理階段因?yàn)閮?nèi)存分區(qū)數(shù)量少,耗時也較短。(STW)

  • 轉(zhuǎn)移階段要處理所有存活的對象,耗時會較長。(STW)

因此,G1 停頓時間的瓶頸主要是標(biāo)記-復(fù)制中的轉(zhuǎn)移階段 STW。為什么轉(zhuǎn)移階段不能和標(biāo)記階段一樣并發(fā)執(zhí)行呢?主要是 G1 未能解決轉(zhuǎn)移過程中準(zhǔn)確定位對象地址的問題。

G1 的 Young GC 和 CMS 的 Young GC,其標(biāo)記-復(fù)制全過程 STW,這里不再詳細(xì)闡述

ZGC 原理

全并發(fā)的ZGC

與CMS中的ParNew和G1類似,ZGC 也采用標(biāo)記-復(fù)制算法,不過 ZGC對該算法做了重大改進(jìn):ZGC 在標(biāo)記、轉(zhuǎn)移和重定位階段幾乎都是并發(fā)的,這是 ZGC 實(shí)現(xiàn)停頓時間小于 10ms 目標(biāo)的最關(guān)鍵原因。

ZGC 垃圾回收周期如下圖所示: 如何理解內(nèi)存布局及GC原理

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

其中,初始標(biāo)記和初始轉(zhuǎn)移分別都只需要掃描所有 GC Roots,其處理時間和 GC Roots 的數(shù)量成正比,一般情況耗時非常短;再標(biāo)記階段 STW 時間很短,最多 1ms,超過 1ms 則再次進(jìn)入并發(fā)標(biāo)記階段。即,ZGC幾乎所有暫停都只依賴于 GC Roots 集合大小,停頓時間不會隨著堆的大小或者活躍對象的大小而增加。與 ZGC 對比,G1的轉(zhuǎn)移階段完全STW的,且停頓時間隨存活對象的大小增加而增加。


ZGC只有三個 STW 階段:初始標(biāo)記 , 再標(biāo)記 , 初始轉(zhuǎn)移 。其中,初始標(biāo)記和初始轉(zhuǎn)移分別都只需要掃描所有 GC Roots,其處理時間和 GC Roots 的數(shù)量成正比,一般情況耗時非常短;再標(biāo)記階段 STW 時間很短,最多1ms,超過1ms則再次進(jìn)入并發(fā)標(biāo)記階段。即,ZGC 幾乎所有暫停都只依賴于GC Roots集合大小,停頓時間不會隨著堆的大小或者活躍對象的大小而增加。與 ZGC 對比,G1 的轉(zhuǎn)移階段完全 STW 的,且停頓時間隨存活對象的大小增加而增加。

ZGC 關(guān)鍵技術(shù)

   ZGC 通過著色指針和讀屏障技術(shù),解決了轉(zhuǎn)移過程中準(zhǔn)確訪問對象的問題,實(shí)現(xiàn)了并發(fā)轉(zhuǎn)移。

大致原理描述如下:并發(fā)轉(zhuǎn)移中“并發(fā)”意味著 GC 線程在轉(zhuǎn)移對象的過程中,應(yīng)用線程也在不停地訪問對象。假設(shè)對象發(fā)生轉(zhuǎn)移,但對象地址未及時更新,那么應(yīng)用線程可能訪問到舊地址,從而造成錯誤。ZGC中,應(yīng)用線程訪問對象將觸發(fā)“讀屏障”,如果發(fā)現(xiàn)對象被移動了,那么“讀屏障”會把讀出來的指針更新到對象的新地址上,這樣應(yīng)用線程始終訪問的都是對象的新地址。那么,JVM 是如何判斷對象被移動過呢?就是利用對象引用的地址,即著色指針。下面介紹著色指針和讀屏障技術(shù)細(xì)節(jié)。

著色指針

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

ZGC 僅支持 64 位系統(tǒng),它把 64 位虛擬地址空間劃分為多個子空間,如下圖所示: 如何理解內(nèi)存布局及GC原理

其中,[0~4TB) 對應(yīng) Java 堆,[4TB ~ 8TB) 稱為 M0 地址空間,[8TB ~ 12TB) 稱為 M1 地址空間,[12TB ~ 16TB) 預(yù)留未使用,[16TB ~ 20TB) 稱為 Remapped 空間。


當(dāng)應(yīng)用程序創(chuàng)建對象時,首先在堆空間申請一個虛擬地址,但該虛擬地址并不會映射到真正的物理地址。ZGC 同時會為該對象在 M0、M1 和 Remapped 地址空間分別申請一個虛擬地址,且這三個虛擬地址對應(yīng)同一個物理地址,但這三個空間在同一時間有且只有一個空間有效。ZGC 之所以設(shè)置三個虛擬地址空間,是因?yàn)樗褂谩翱臻g換時間”思想,去降低 GC 停頓時間?!翱臻g換時間”中的空間是虛擬空間,而不是真正的物理空間。后續(xù)章節(jié)將詳細(xì)介紹這三個空間的切換過程。


如何理解內(nèi)存布局及GC原理

與上述地址空間劃分相對應(yīng),ZGC 實(shí)際僅使用 64 位地址空間的第 0~41 位,而第 42~45 位存儲元數(shù)據(jù),第 47~63 位固定為 0。ZGC 將對象存活信息存儲在 42~45 位中,這與傳統(tǒng)的垃圾回收并將對象存活信息放在對象頭中完全不同。

讀屏障

讀屏障是 JVM 向應(yīng)用代碼插入一小段代碼的技術(shù)。當(dāng)應(yīng)用線程從堆中讀取對象引用時,就會執(zhí)行這段代碼。需要注意的是,僅“從堆中讀取對象引用”才會觸發(fā)這段代碼。

讀屏障示例:
Object o = obj.FieldA   // 從堆中讀取引用,需要加入屏障
<Load barrier>
Object p = o  // 無需加入屏障,因?yàn)椴皇菑亩阎凶x取引用
o.dosomething() // 無需加入屏障,因?yàn)椴皇菑亩阎凶x取引用
int i =  obj.FieldB  //無需加入屏障,因?yàn)椴皇菍ο笠?/pre>

ZGC 中讀屏障的代碼作用 :在對象標(biāo)記和轉(zhuǎn)移過程中,用于確定對象的引用地址是否滿足條件,并作出相應(yīng)動作。

ZGC 并發(fā)處理演示

接下來詳細(xì)介紹 ZGC 一次垃圾回收周期中地址視圖的切換過程:

  • 初始化 :ZGC 初始化之后,整個內(nèi)存空間的地址視圖被設(shè)置為 Remapped。程序正常運(yùn)行,在內(nèi)存中分配對象,滿足一定條件后垃圾回收啟動,此時進(jìn)入標(biāo)記階段。

  • 并發(fā)標(biāo)記階段 :第一次進(jìn)入標(biāo)記階段時視圖為 M0,如果對象被 GC 標(biāo)記線程或者應(yīng)用線程訪問過,那么就將對象的地址視圖從 Remapped 調(diào)整為 M0。所以,在標(biāo)記階段結(jié)束之后,對象的地址要么是 M0 視圖,要么是 Remapped。如果對象的地址是 M0 視圖,那么說明對象是活躍的;如果對象的地址是 Remapped 視圖,說明對象是不活躍的。

  • 并發(fā)轉(zhuǎn)移階段 :標(biāo)記結(jié)束后就進(jìn)入轉(zhuǎn)移階段,此時地址視圖再次被設(shè)置為 Remapped。如果對象被 GC 轉(zhuǎn)移線程或者應(yīng)用線程訪問過,那么就將對象的地址視圖從 M0 調(diào)整為 Remapped。

  • 其實(shí),在標(biāo)記階段存在兩個地址視圖 M0 和 M1,上面的過程顯示只用了一個地址視圖。之所以設(shè)計(jì)成兩個,是為了區(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)記階段:將對象設(shè)置為已標(biāo)記,傳統(tǒng)的垃圾回收器需要進(jìn)行一次內(nèi)存訪問,并將對象存活信息放在對象頭中;而在 ZGC 中,只需要設(shè)置指針地址的第 42~45 位即可,并且因?yàn)槭羌拇嫫髟L問,所以速度比訪問內(nèi)存更快。

到此,關(guān)于“如何理解內(nèi)存布局及GC原理”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

gc
AI