原文地址:https://xeblog.cn/articles/24
新生代收集器
新生代均采用
復(fù)制
算法來(lái)回收內(nèi)存累驮。
Serial 收集器
最基本的樊拓、發(fā)展歷史最悠久的單線(xiàn)程的收集器。在進(jìn)行垃圾收集時(shí)坟桅,必須暫停其它所有的工作線(xiàn)程(Stop The World)页屠,直到它收集結(jié)束纵穿。它是 JVM
運(yùn)行在 Client
模式下的默認(rèn)新生代收集器,它比其它單線(xiàn)程的收集器更簡(jiǎn)單收毫、更高效攻走∫罂保可與 CMS 收集器
配合工作。
ParNew 收集器
Serial 收集器
的多線(xiàn)程版本昔搂。它是許多運(yùn)行在 Server
模式下的虛擬機(jī)首選的新生代收集器玲销,在使用 -XX:+UseConcMarkSweepGC
選項(xiàng)后的默認(rèn)新生代收集器,也可以通過(guò) -XX:+UseParNewGC
選項(xiàng)強(qiáng)制指定它摘符。它除了是多線(xiàn)程收集之外贤斜,其它和 Serial 收集器
基本一樣,它默認(rèn)開(kāi)啟的收集線(xiàn)程數(shù)與 CPU
的數(shù)量相同逛裤,在 CPU
非常多的環(huán)境下瘩绒,可通過(guò) -XX:ParallelGCThreads
參數(shù)限制垃圾收集的線(xiàn)程數(shù)〈澹可與 CMS 收集器
配合工作锁荔。
Parallel Scavenge 收集器
并行的多線(xiàn)程收集器,它的目標(biāo)是達(dá)到一個(gè)可控的吞吐量(吞吐量是 CPU
用于運(yùn)行用戶(hù)代碼的時(shí)間與 CPU
總消耗時(shí)間的比值)蝙砌。
吞吐量 = 運(yùn)行用戶(hù)代碼的時(shí)間 / (運(yùn)行用戶(hù)代碼的時(shí)間 + 垃圾收集時(shí)間)
高吞吐量可以高效的利用 CPU
時(shí)間阳堕,盡快的完成程序的運(yùn)算任務(wù),主要適合在后臺(tái)運(yùn)算而不需要太多交互的任務(wù)拍霜。Parallel Scavenge 收集器
提供了兩個(gè)參數(shù)用于精確控制吞吐量: -XX:MaxGCPauseMillis
和 -XX:GCTimeRatio
嘱丢。
最大垃圾收集停頓時(shí)間:-XX:MaxGCPauseMillis
允許一個(gè)大于0的毫秒數(shù),收集器將盡可能保證內(nèi)存回收花費(fèi)時(shí)間不超過(guò)這個(gè)設(shè)定的值祠饺,它是以犧牲吞吐量和新生代空間來(lái)縮短 GC
停頓時(shí)間的越驻。
吞吐量大小:-XX:GCTimeRatio
允許一個(gè)大于0且小于100的整數(shù)道偷,垃圾收集時(shí)間占總時(shí)間的比率缀旁。
GC自適應(yīng)調(diào)節(jié)參數(shù):-XX:+UseAdaptiveSizePolicy
這是一個(gè)開(kāi)關(guān)參數(shù),當(dāng)它打開(kāi)后勺鸦,就不需要手動(dòng)指定新生代的大胁⑽ (-Xmn),Eden
與 Survivor
區(qū)的比例(-XX:SurvivorRatio)换途、晉升老年代對(duì)象年齡(-XX:PretenureSizeThreshold)等細(xì)節(jié)參數(shù)了懊渡,虛擬機(jī)會(huì)根據(jù)當(dāng)前系統(tǒng)的運(yùn)行情況收集性能監(jiān)控信息,動(dòng)態(tài)調(diào)整這些參數(shù)以提供最合適的停頓時(shí)間或最大的吞吐量军拟。
老年代收集器
老年代采用
標(biāo)記-整理
或標(biāo)記-清除
算法來(lái)回收內(nèi)存剃执。
Serial Old 收集器
它是 Serial 收集器
的老年代版本,也是一個(gè)單線(xiàn)程收集器懈息,使用 標(biāo)記-整理
算法肾档。這個(gè)收集器的主要意義也是在于給 Client
模式下的虛擬機(jī)使用,如果是在 Server
模式下,那么它主要還有兩大用途:
- 在
JDK1.5
以及之前版本中與Parallel Scavenge 收集器
搭配使用怒见。 - 作為
CMS收集器
的后備預(yù)案俗慈,在并發(fā)收集發(fā)生Concurrent Mode Failure
時(shí)使用。
Parallel Old 收集器
它是 Parallel Scavenge 收集器
的老年代版本遣耍,使用多線(xiàn)程和 標(biāo)記-整理
算法闺阱。
CMS 收集器 (Concurrent Mark Sweep)
它是一種并發(fā)的、以獲取最短回收停頓時(shí)間為目標(biāo)的收集器配阵,使用 標(biāo)記-清除
算法實(shí)現(xiàn)的馏颂。運(yùn)行過(guò)程較為復(fù)雜示血,整個(gè)過(guò)程分為4個(gè)步驟:
- 初始標(biāo)記(CMS Initial Marking)
- 并發(fā)標(biāo)記(CMS Concurrent marking)
- 重新標(biāo)記(CMS ReMarking)
- 并發(fā)清除(CMS Concurrent Sweep)
初始標(biāo)記棋傍、重新標(biāo)記仍需要暫停其它所有的工作線(xiàn)程,初始標(biāo)記僅僅只是標(biāo)記一下 GC Roots
能直接關(guān)聯(lián)到的對(duì)象难审,速度很快瘫拣。并發(fā)標(biāo)記階段就是進(jìn)行 GC Roots
的可達(dá)性分析過(guò)程,而重新標(biāo)記階段則是為了修正并發(fā)標(biāo)記期間因用戶(hù)線(xiàn)程繼續(xù)運(yùn)作而導(dǎo)致標(biāo)記產(chǎn)生變動(dòng)的那一部分對(duì)象的標(biāo)記記錄告喊,這個(gè)階段的停頓時(shí)間一般會(huì)比初始標(biāo)記階段稍長(zhǎng)一些麸拄,但遠(yuǎn)比并發(fā)標(biāo)記的時(shí)間短。CMS 收集器
存在3個(gè)明顯的缺點(diǎn):
-
CMS收集器
會(huì)占用一部分線(xiàn)程而導(dǎo)致應(yīng)用程序變慢黔姜,總吞吐量會(huì)降低拢切。CMS
默認(rèn)啟功的回收線(xiàn)程數(shù)是(CPU數(shù)量 + 3)/ 4
,相當(dāng)于當(dāng)CPU
在4個(gè)以上時(shí)秆吵,并發(fā)回收時(shí)垃圾收集線(xiàn)程不少于25%
的CPU
資源淮椰,并隨著CPU
數(shù)量的增加而下降。當(dāng)CPU
不足4個(gè)時(shí)纳寂,CMS
對(duì)用戶(hù)線(xiàn)程的影響就可能變得更大主穗。 -
CMS收集器
無(wú)法處理浮動(dòng)垃圾,可能出現(xiàn)Concurrent Mode Failure
失敗而導(dǎo)致另一次Full GC
的產(chǎn)生毙芜。由于CMS
并發(fā)清除階段用戶(hù)線(xiàn)程還在運(yùn)行著忽媒,伴隨程序運(yùn)行自然就還會(huì)有新的垃圾不斷產(chǎn)生,這一部分垃圾出現(xiàn)在標(biāo)記過(guò)程之后腋粥,CMS
無(wú)法在當(dāng)次收集中處理掉它們晦雨,只好留在下一次GC
時(shí)再清理掉,這一部分垃圾就稱(chēng)為浮動(dòng)垃圾隘冲。 - 由于
CMS收集器
使用的是標(biāo)記-清除
算法闹瞧,所以垃圾回收后會(huì)產(chǎn)生大量的空間碎片。CMS
提供-XX:+UseCMSCompactAtFullCollection
的開(kāi)關(guān)參數(shù)(默認(rèn)開(kāi)啟)对嚼,用于在CMS
收集器頂不住要進(jìn)行Full GC
時(shí)開(kāi)啟內(nèi)存碎片的合并整理過(guò)程夹抗,這個(gè)過(guò)程是無(wú)法并發(fā)執(zhí)行的,雖然空間碎片沒(méi)了纵竖,但是停頓時(shí)間不得不變長(zhǎng)漠烧。
全干工程師:G1收集器
G1收集器
是當(dāng)今收集器技術(shù)發(fā)展的最前沿成果之一杏愤。
上面所介紹的收集器,都只是負(fù)責(zé) Java堆
中的一部分內(nèi)存(新生代或老年代)已脓,而 G1
就不同了珊楼,它全干。
G1
將整個(gè) Java堆
劃分為多個(gè)大小相等的獨(dú)立區(qū)域(Region)度液,雖然還保留有新生代和老年代的概念厕宗,但是這兩部分內(nèi)存不再是物理隔離的,它們都是一部分不需要連續(xù)的 Region
的集合了堕担。
具備的特點(diǎn):
- 并行與并發(fā):
G1
能充分利用多CPU
已慢、多核環(huán)境下的硬件優(yōu)勢(shì),使用多個(gè)CPU
來(lái)縮短Stop The World
的停頓時(shí)間霹购。 - 分代收集(全干工程師):
G1
可以不需要與其它收集器配合就能獨(dú)立管理整個(gè)GC堆
佑惠,根據(jù)分代收集
的概念采用不同的方式去處理。 - 空間整合:基于
標(biāo)記-整理
和復(fù)制
算法齐疙,不會(huì)產(chǎn)生內(nèi)存空間碎片膜楷。 - 可預(yù)測(cè)的停頓:
G1
可以建立可預(yù)測(cè)的停頓時(shí)間模型,將垃圾收集消耗的時(shí)間限制在一定的時(shí)間內(nèi)贞奋。
可預(yù)測(cè)的停頓時(shí)間模型
G1
之所以能夠建立可預(yù)測(cè)的停頓時(shí)間模型赌厅,是因?yàn)樗梢杂杏?jì)劃的避免在整個(gè) Java堆
中進(jìn)行全區(qū)域的垃圾收集。G1
通過(guò)跟蹤各個(gè) Region
里面的內(nèi)存堆積的價(jià)值大薪嗡(回收所獲得的空間大小以及回收所需時(shí)間的經(jīng)驗(yàn)值)特愿,在后臺(tái)維護(hù)一個(gè)優(yōu)先回收隊(duì)列,每次根據(jù)允許的收集時(shí)間催训,優(yōu)先回收價(jià)值最大的 Region
洽议。這種使用 Region
劃分內(nèi)存空間以及有優(yōu)先級(jí)的區(qū)域回收方式,保證了 G1
收集器在有限的時(shí)間內(nèi)可以獲取盡可能高的收集效率漫拭。
避免全堆掃描且保證準(zhǔn)確性
在 G1
收集器中亚兄,Region
之間的對(duì)象引用以及其它收集器中的新生代與老年代之間的對(duì)象引用,虛擬機(jī)都是使用 Remembered Set
來(lái)避免全堆掃描的采驻。G1
中的每一個(gè) Region
都有一個(gè)與之對(duì)應(yīng)的 Remembered Set
审胚,在對(duì) Reference
類(lèi)型的數(shù)據(jù)進(jìn)行寫(xiě)操作的時(shí)間,虛擬機(jī)會(huì)產(chǎn)生一個(gè)屏障暫時(shí)中斷寫(xiě)操作礼旅,然后檢查這個(gè)引用的對(duì)象是否處于不同的 Region
之中膳叨,如果是,就會(huì)通過(guò) CardTable
把相關(guān)引用信息記錄到被引用對(duì)象所屬的 Region
的 Remembered Set
中痘系。當(dāng)進(jìn)行內(nèi)存回收時(shí)菲嘴,在 GC Roots
的枚舉范圍內(nèi)加入 Remembered Set
即可保證不對(duì)全堆掃描也不會(huì)有遺漏。
G1運(yùn)行過(guò)程
如果不計(jì)算維護(hù) Remembered Set
的操作,G1
收集器的運(yùn)行過(guò)程大致可以分為4個(gè)步驟:
- 初始標(biāo)記(G1 Initial Marking)
- 并發(fā)標(biāo)記(G1 Concurrent Marking)
- 最終標(biāo)記(G1 Final Marking)
- 篩選回收(G1 Live Data Counting And Evacuation)
初始標(biāo)記階段只是簡(jiǎn)單的標(biāo)記一下 GC Roots
能直接關(guān)聯(lián)到的對(duì)象龄坪,并且修改TAMS(Next Top At Mark Start)的值昭雌,讓下一階段用戶(hù)程序并發(fā)運(yùn)行時(shí),能在正確可用的 Region
中創(chuàng)建新對(duì)象健田,這個(gè)階段需要停頓線(xiàn)程烛卧,但耗時(shí)很短。并發(fā)標(biāo)記階段也是進(jìn)行 GC Roots
的可達(dá)性分析過(guò)程妓局,耗時(shí)很長(zhǎng)但是可與用戶(hù)程序一起工作总放。最終標(biāo)記階段是為了修正并發(fā)標(biāo)記期間因用戶(hù)線(xiàn)程繼續(xù)運(yùn)作而導(dǎo)致標(biāo)記產(chǎn)生變動(dòng)的那一部分對(duì)象的標(biāo)記記錄,虛擬機(jī)將這段時(shí)間對(duì)象變化記錄在線(xiàn)程的 Remembered Set Logs
中好爬,這個(gè)階段需要把 Remembered Set Logs
中的數(shù)據(jù)合并到 Remembered Set
里局雄,需要停頓線(xiàn)程,但是可以并行執(zhí)行抵拘。
最后的篩選回收階段會(huì)對(duì) Region
的回收價(jià)值和成本進(jìn)行排序哎榴,根據(jù)用戶(hù)所期望的 GC
停頓時(shí)間來(lái)制定回收計(jì)劃型豁。
查看JVM所使用的收集器
java -XX:+PrintCommandLineFlags -version
在終端執(zhí)行上述命令后僵蛛,即可查看 JVM
所使用的收集器。
-XX:+UseParallelGC : 是虛擬機(jī)運(yùn)行在 Server
模式下的默認(rèn)值迎变,打開(kāi)此開(kāi)關(guān)后充尉,使用 Parallel Scavenge + Serial Old (PS MarkSweep)
的收集器組合進(jìn)行內(nèi)存回收。
參考
- 《深入理解Java虛擬機(jī):JVM高級(jí)特性與最佳實(shí)踐 第二版》