這三大特性,讓 G1 取代了 CMS!
?大家好,我是樹(shù)哥。
之前我們聊過(guò) CMS 回收器,但那時(shí)候我們說(shuō) CMS 回收器已經(jīng)落伍了,現(xiàn)在應(yīng)該是用 G1 回收器的時(shí)候了。那么 G1 回收器到底有什么魔力,它比 CMS 回收器相比強(qiáng)在哪里呢?今天,就讓樹(shù)哥帶大家盤一盤!
文章思維導(dǎo)圖
G1 回收器的歷史
G1(Garbage-First)回收器早在 JDK1.7 的時(shí)候就確定要做,但直到 JDK7u4 的時(shí)候才正式推出使用。等到了 JDK9 之后變成了默認(rèn)的垃圾回收器,同時(shí)廢棄了 CMS 回收器。
G1 回收器特性
G1 回收器是一款面向服務(wù)端應(yīng)用的垃圾回收器,它的長(zhǎng)期使命是替換 CMS 回收器。G1 回收器于 CMS 回收器相比,它們有相似的地方,例如:都是關(guān)注 GC 停頓時(shí)間的回收器,都采用了分代回收的思想。
但從整體的實(shí)現(xiàn)上來(lái)看,G1 回收器做了非常多的改進(jìn),可以說(shuō)是對(duì) CMS 回收器的全面改進(jìn)。相對(duì)于 CMS 回收器來(lái)說(shuō),G1 回收器有下面幾個(gè)不同的地方:
- 采用化整為零的分區(qū)思想
- 采用標(biāo)記 - 整理的垃圾回收算法
- 可預(yù)測(cè)的 GC 停頓時(shí)間
分區(qū)思想
對(duì)于 CMS 及之前的回收器來(lái)說(shuō),其 JVM 內(nèi)存空間按照分代的思路劃分成物理連續(xù)的一大片區(qū)域,如下圖所示。
但在 G1 回收器中,雖然也采用了分代的思路,但其并沒(méi)有為其分配一塊連續(xù)的內(nèi)存,而是將整塊內(nèi)存化整為零拆分成一個(gè)個(gè) Region,如下圖所示。
正如上圖所示,G1 回收器不再為年輕代和老年代劃分大塊的內(nèi)存,而是劃分成了一個(gè)個(gè)的 Region,每個(gè) Region 被標(biāo)記成年輕代或者老年代。在 G1 中,還多了一個(gè) Humongous 區(qū)域,其是為了優(yōu)化大對(duì)象的分配而誕生的。
G1 回收器化整為零的 Region 設(shè)計(jì)思想,是 G1 回收器比 CMS 回收器強(qiáng)大的核心。 通過(guò)將大塊的內(nèi)存化整為零,G1 回收器能夠更加靈活地控制 GC 停頓時(shí)間,并且也解決了 CMS 回收器存在的內(nèi)存碎片問(wèn)題以及大內(nèi)存下的長(zhǎng) GC 停頓時(shí)間問(wèn)題。
標(biāo)記 - 整理算法
G1 回收器與 CMS 回收器的另一個(gè)很大的區(qū)別是:G1 回收器使用的是「標(biāo)記 - 整理」算法,而 CMS 回收器使用的是「標(biāo)記 - 清除」算法。 因此,CMS 回收器會(huì)產(chǎn)生非常多的內(nèi)存碎片,而 G1 回收器則沒(méi)有這個(gè)困擾。
有些小伙伴會(huì)問(wèn):那為什么 CMS 回收器不用「標(biāo)記 - 整理」算法呢?
很簡(jiǎn)單,因?yàn)?CMS 回收器的老年代很大,使用「標(biāo)記 - 整理」算法需要耗費(fèi)很長(zhǎng)的 GC 停頓時(shí)間,這會(huì)導(dǎo)致接口響應(yīng)時(shí)間變長(zhǎng)。實(shí)際上 CMS 回收器后續(xù)提供了 -XX:+UseCMSCompactAtFullCollection 參數(shù)去實(shí)現(xiàn)內(nèi)存壓縮,但在內(nèi)存壓縮的時(shí)候 GC 停頓時(shí)間會(huì)很長(zhǎng),從而導(dǎo)致接口響應(yīng)時(shí)間變長(zhǎng)。
好奇寶寶又問(wèn)了:G1 回收器也用的是「標(biāo)記 - 整理」算法,為啥就不會(huì)導(dǎo)致長(zhǎng) GC 停頓時(shí)間呢?
很簡(jiǎn)單,因?yàn)?G1 回收器使用了分 Region 的思想,其將大塊的內(nèi)存化整為零成為 Region。此外,其還維護(hù)了一個(gè)待回收 Region 列表,可以選擇回收性價(jià)比最高的 Region 進(jìn)行回收,從而實(shí)現(xiàn)對(duì) GC 停頓時(shí)間的靈活控制。
看到了么,G1 回收器化整為零的 Region 設(shè)計(jì)思想,真的是 G1 回收器的大殺器!
可預(yù)測(cè)的停頓時(shí)間
G1 回收器對(duì)于 CMS 而言還有一個(gè)很大的優(yōu)勢(shì),即能建立可預(yù)測(cè)的停頓時(shí)間模型,能讓使用者明確指定在一個(gè)長(zhǎng)度為 M 毫秒的時(shí)間片段內(nèi),消耗在垃圾收集上的時(shí)間不得超過(guò) N 毫秒。對(duì)于該特性現(xiàn)在還用得比較少,大家了解一下就可以了。
垃圾回收過(guò)程
比起 CMS 回收器來(lái)說(shuō),G1 回收器的垃圾回收過(guò)程就比較特別了,其采用了「年輕代收集」和「混合收集」兩種垃圾回收方式。
年輕代收集
在應(yīng)用剛剛啟動(dòng)的時(shí)候,流量慢慢進(jìn)來(lái),JVM 開(kāi)始生成對(duì)象。G1 會(huì)選擇一個(gè)分區(qū)并指定 eden 分區(qū),當(dāng)這塊分區(qū)用滿之后,G1 會(huì)選一個(gè)新的分區(qū)作為 eden 分區(qū)。這個(gè)操作會(huì)一直進(jìn)行下去,一直到達(dá)到 eden 分區(qū)的上限,接著觸發(fā)一次年輕代收集。
年代收集采用的是「復(fù)制算法」,其首先使用單 eden、雙 survivor 遷移存活對(duì)象。在遷移過(guò)程中,會(huì)根據(jù)對(duì)象年齡以及其他特性,將對(duì)象晉升到老年代分區(qū)中,原有的年輕代分區(qū)會(huì)被整個(gè)回收掉。這個(gè)過(guò)程涉及到的規(guī)則和 CMS 回收器類似,只是 G1 回收器將內(nèi)存化整為零了而已。
混合收集
隨著時(shí)間推移,越來(lái)越多的對(duì)象晉升到老年代中。當(dāng)老年代占比(占 Java 堆內(nèi)存的比例)達(dá)到 InitiatingHeapOccupancyPercent 參數(shù)之后,JVM 便會(huì)觸發(fā)「混合收集」進(jìn)行垃圾收集。要注意的是:混合收集會(huì)收集年輕代和部分老年代的內(nèi)存,其并不等同于 Full GC。Full GC 會(huì)回收整個(gè)老年代內(nèi)存。
對(duì)于混合收集方式來(lái)說(shuō),其收集過(guò)程可以分為 4 個(gè)階段:
- 初始標(biāo)記
- 并發(fā)標(biāo)記
- 最終標(biāo)記
- 篩選回收
初始標(biāo)記。 該階段與 CMS 回收器一樣,都只是簡(jiǎn)單標(biāo)記一下 GC Roots 能直接關(guān)聯(lián)到的對(duì)象,讓后續(xù) GC 回收線程能與用戶線程并發(fā)執(zhí)行。初始標(biāo)記階段是需要「Stop the World」的。
并發(fā)標(biāo)記。 該階段與 CMS 回收器一樣,它從 GC Root 開(kāi)始對(duì)堆中對(duì)象進(jìn)行可達(dá)性分析,找出存活的對(duì)象,這階段耗時(shí)很長(zhǎng),但可與用戶程序并發(fā)執(zhí)行,不需要「Stop the World」。
最終標(biāo)記。 該階段與 CMS 回收器一樣,它是為了修正在并發(fā)標(biāo)記期間因用戶程序繼續(xù)運(yùn)作而導(dǎo)致引用發(fā)生變化的問(wèn)題。只是 G1 回收器采用了不同的方式去實(shí)現(xiàn),在這個(gè)階段是需要「Stop the World」的。
篩選回收。 該階段與 CMS 回收器的并發(fā)清除一樣,它是去將標(biāo)記為垃圾的對(duì)象清除掉。只是對(duì)于 G1 回收器來(lái)說(shuō),它會(huì)維護(hù)各個(gè) Region 的回收價(jià)值和成本,隨后根據(jù)用戶期望的 GC 停頓時(shí)間來(lái)指定回收計(jì)劃。
來(lái)自《深入理解 Java 虛擬機(jī)》
整體看下來(lái),我們會(huì)發(fā)現(xiàn) G1 回收器的混合收集過(guò)程與 CMS 回收器非常類似,都經(jīng)歷初始標(biāo)記、并發(fā)標(biāo)記、最終標(biāo)記、篩選回收(并發(fā)清除)幾個(gè)階段。
總結(jié)
從 JDK7 正式推出到 JDK9 成為默認(rèn)的垃圾收集器,G1 回收器用了兩代人的時(shí)間打敗了 CMS 回收器。
從 G1 回收器的實(shí)現(xiàn)來(lái)看,其開(kāi)創(chuàng)性的化整為零的 Region 設(shè)計(jì)思想,無(wú)疑是其打敗 CMS 回收器的秘訣。通過(guò)該設(shè)計(jì)思想,G1 回收器得以更加靈活地控制 GC 停頓時(shí)間,同時(shí)也可以實(shí)現(xiàn)更加高效、復(fù)雜的功能,例如:根據(jù)回收空間和耗時(shí)選擇最佳的回收 Region、預(yù)測(cè) GC 停頓時(shí)間等。
參考資料
- 名字解釋不錯(cuò)!VIP!搞懂 G1 垃圾收集器 - GrimMjx - 博客園
- 關(guān)于 GC 過(guò)程,寫得不錯(cuò)!VIP!Java Hotspot G1 GC 的一些關(guān)鍵技術(shù) - 美團(tuán)技術(shù)團(tuán)隊(duì)
- 08 大廠面試題:有了 G1 還需要其他垃圾回收器嗎?.md
- 官方資料!VIP!Garbage First Garbage Collector Tuning | Oracle 中國(guó)
- 官方資料!VIP!垃圾回收期的推薦使用場(chǎng)景!Java HotSpot Garbage Collection
- 還行!VIP!5 張圖帶你徹底理解 G1 垃圾收集器 - 51CTO.COM
- G1 垃圾收集器詳解 - 掘金
- 深入理解 Java 虛擬機(jī)系列 --12 垃圾回收篇 03 -- 常用的垃圾回收器詳解 - 掘金
- 深入理解 JAVA 垃圾收集器 CMS,G1 工作流程原理 - 掘金
- GC - Java 垃圾回收器之 G1 詳解 | Java 全棧知識(shí)體系
- VIP!有美團(tuán)的具體實(shí)踐!GC - Java 垃圾回收器之 ZGC 詳解 | Java 全棧知識(shí)體系
- 《深入理解 Java 虛擬機(jī)》
- CMS 垃圾回收器存在的問(wèn)題及解決方案 - 代碼先鋒網(wǎng)?