Java8 的 G1 垃圾回收器相對于之前的 CMS 有什么特別的呢?
本文轉(zhuǎn)載自微信公眾號「Java極客技術(shù)」,作者鴨血粉絲。轉(zhuǎn)載本文請聯(lián)系Java極客技術(shù)公眾號。
CMS
CMS 垃圾回收器,全稱 Concurrent Mark Sweep 并發(fā)標(biāo)記-清除,從名字上面我們也可以看出這個垃圾回收器是基于標(biāo)記清除算法實現(xiàn)的。首先"并發(fā)"表示 GC 線程可以和用戶線程并發(fā)執(zhí)行,同時既然是標(biāo)記-清除算法,說明這個垃圾回收器會產(chǎn)生很多碎片,這是標(biāo)記-清除算法的缺點。同時 CMS 是作用于老年代的,老年代的垃圾回收頻率相對年輕代會低一點。
CMS 的垃圾回收有四個過程
- 初始標(biāo)記:
- 并發(fā)標(biāo)記:
- 重新標(biāo)記:
- 并發(fā)清除:
初始標(biāo)記的時候是一個 STW (stop the world)的過程,所有的用戶線程都會停止,這個時候只是標(biāo)記一下 GC Roots 能直接達(dá)到的對象,由于只是標(biāo)記一層所以整個速度相對會比較快。
并發(fā)標(biāo)記是一個 GC Roots 掃描的過程,會掃描整個鏈路標(biāo)記可以回收的對象;由于整個的鏈路會比較長,所以相對會耗時久一點,不過由于這個過程是并發(fā)的,所以對用戶線程運行是沒有影響的。
重新標(biāo)記顧名思義是一個再次標(biāo)記的過程,同時也是會 STW,之所以會有這個重新標(biāo)記的過程,是因為在上一步并發(fā)標(biāo)記的過程中,用戶線程依舊在運行,所以對象的引用關(guān)系會發(fā)生變化同時在運行的時候也會產(chǎn)生新的垃圾。這里只會標(biāo)記在上一步有發(fā)生變化的對象,雖然會 STW 不過速度也較快。
并發(fā)清除是最后一個階段,這個階段由于需要清除之前掃描的所有垃圾對象,所以會相對比較耗時,不過這個階段是可以并發(fā)進(jìn)行的所以對用戶線程的運行不會有影響。
經(jīng)過上面的四個過程就完成了一次完整的 GC,前面我們提到整個 CMS 垃圾回收器是基于標(biāo)記-清除算法的,先通過三個過程標(biāo)記出需要清理的對象,然后再進(jìn)行清理。整個過程中初始標(biāo)記和重新標(biāo)記會觸發(fā) STW,其他兩個階段是并發(fā)進(jìn)行的。標(biāo)記-清除算法會產(chǎn)生內(nèi)存碎片,所以不適合需要頻繁回收的年輕代,所以只適合老年代。產(chǎn)生碎片是 CMS 的缺點,并發(fā)是 CMS 的優(yōu)點,畢竟任何一個收集器都會有優(yōu)缺點。
G1
前面我們聊完了 CMS,接下來我們聊一下 G1,G1 全稱 Garbage First,在講 G1 垃圾回收器的細(xì)節(jié)之前,我們首先要知道的是 G1 對整個堆的空間做了重新的定義。G1 中的老年代和年輕代已經(jīng)不再是物理隔離的了,而是邏輯隔離。在 G1 中整個堆空間被分成了一個個相同大小的 Region 塊,多個 Region 塊在邏輯上組成了年輕代和老年代。
這樣做的目的是因為在進(jìn)行垃圾回收的時候不需要進(jìn)行整個堆空間的掃描,同時可以根據(jù)指定停頓時間來進(jìn)行垃圾回收。G1 會將每個 Region 的回收成本進(jìn)行量化,從而達(dá)到一個成本控制,可以在限定的停頓時間內(nèi)完成回收,這是 G1 的最大的特點。
G1 回收也分為四個過程:
- 初始標(biāo)記:初始標(biāo)記與 CMS 也是只掃描 GC Roots 直達(dá)的對象,這階段同樣也要 STW,不過時間也很短;
- 并發(fā)標(biāo)記:從 GC Roots 開始堆中對象進(jìn)行可達(dá)性分析,找出存活的對象,這個階段耗時較長,但是可以與用戶程序并發(fā)執(zhí)行;
- 最終標(biāo)記:最終標(biāo)記和 CMS 的重新標(biāo)記的思路一直,也是為了修正并發(fā)標(biāo)記期間由于用戶程序并發(fā)運行而導(dǎo)致標(biāo)記產(chǎn)生變動的那一部分對象,不過不同的是 G1 會將這段時間對象變化記錄在線程 Remembered Set Logs 里面,最終標(biāo)記階段需要把 Remembered Set Logs 的數(shù)據(jù)合并到 Remembered Set 中,這個階段需要停頓線程,不過是可并行執(zhí)行;
- 篩選回收:最后一步篩選回收是 G1 與 CMS 最大的不同之處,G1 首先會對各個需要回收的 Region 代價進(jìn)行量化和排序,在結(jié)合用戶所期望的 GC 停頓時間來制定回收計劃,通過-XX:MaxGCPauseMillis 參數(shù)來指定期望的回收時間。這個階段也可以做到與用戶程序一起并發(fā)執(zhí)行,但是因為只回收一部分 Region,時間是用戶可控制的,而且停頓用戶線程將大幅提高收集效率。
上面提到了一個 Remembered Set 記憶集,是用來記錄對象引用的,在并發(fā)標(biāo)記的時候有對象引用發(fā)生變更的時候會記錄到這里,等到最終標(biāo)記的時候進(jìn)行修正。整體上來看 G1 采用的是標(biāo)記-整理的算法來進(jìn)行垃圾回收,也不會像 CMS 那樣會產(chǎn)生內(nèi)容碎片,所以 G1 同時可以進(jìn)行年輕代和老年代的垃圾回收,相比 CMS 會更靈活一點,而且也因為 G1 將內(nèi)存劃分成 Region 了,也不會造成復(fù)制算法帶來的空間浪費的問題。
總結(jié)
首先CMS 和 G1 都是并發(fā)和分代的垃圾回收器,并且都是低延遲的;CMS 是基于標(biāo)記-清除算法的,只適合在年輕代使用,不可預(yù)測停頓時間,同時年輕代和老年代是物理隔離的。G1 是基于標(biāo)記-整理的高吞吐,可預(yù)測停頓時間的垃圾回收器,可以同時使用在年輕代和老年代,同時年輕代和老年代是邏輯隔離的。
| 特點 | G1 | CMS |
|---|---|---|
| 算法 | 標(biāo)記-整理 | 標(biāo)記-清除 |
| 年輕代和老年代隔離方式 | 邏輯隔離 | 物理隔離 |
| 停頓時間可預(yù)測行 | 是 | 否 |
| 并發(fā)和分代 | 支持 | 支持 |
| 吞吐量 | 高 | 低 |
| 使用場景 | 年輕代,老年代 | 年輕代 |
| 低延時 | 是 | 是 |





























