如果說收集算法是內(nèi)存回收的方法論嬉愧,那么垃圾收集器就是內(nèi)存回收的實(shí)踐者。
這7種作用于不同分代的垃圾收集器喉前,如果兩個(gè)收集器之間有連線没酣,就說明它們可以搭配使用王财,收集器所處的位置表示它們是屬于新生代收集器或老年代收集器。
Serial收集器
Serial收集器是一個(gè)單線程工作的收集器裕便,但它的“單線程”的意義不僅僅是它只會(huì)使用一個(gè)處理器或一個(gè)收集線程去完成垃圾收集工作绒净,更重要的是強(qiáng)調(diào)它在進(jìn)行垃圾回收的時(shí)候,必須暫停其他所有工作線程偿衰,直到它回收結(jié)束為止挂疆。
“Stop The World”這項(xiàng)工作是由虛擬機(jī)在后臺(tái)自動(dòng)發(fā)起完成的,在用戶不可知下翎、不可控的情況下缤言,把用戶正常工作的線程全部停掉,這對(duì)很多應(yīng)用來說是不能接受的漏设。
從JDK1.3到現(xiàn)在最新的JDK13,HotSpot虛擬機(jī)開發(fā)團(tuán)隊(duì)為消除或者降低用戶線程因垃圾收集而導(dǎo)致停頓的努力一直在持續(xù)進(jìn)行著墨闲,從Serial收集器到Parallel收集器今妄,到Concurrent Mark Sweep(CMS)和Garbage First(G1)收集器郑口,到現(xiàn)在收集器最前沿成功Shenandoah和ZGC等,用戶線程的停頓時(shí)間在持續(xù)縮短盾鳞,但仍然沒辦法徹底消除犬性。
Serial依然是Hotspot虛擬機(jī)運(yùn)行在客戶端模式下的默認(rèn)新生代收集器,它優(yōu)于其他收集器的地方是簡(jiǎn)單而高效(與其他收集器的單線程相比)腾仅,是所有收集器額外內(nèi)存消耗最小的乒裆,由于沒有線程交互的開銷,專心做垃圾收集自然可以獲得最高的單線程收集效率推励。
ParNew收集器
ParNew收集器是Serial收集器的多線程并行版本鹤耍,除了使用多條線程進(jìn)行垃圾收集之外,其余的行為包括Serial收集器可用的所有控制參數(shù)(例如:-XX:SurvivorRatio验辞、-XX:PretenureSizeThreshold稿黄、-XX:HandlePromotionFailure等)、收集算法跌造、Stop The World杆怕、對(duì)象分配規(guī)則、回收策略等都與Serial收集器完全一致壳贪。
ParNew是運(yùn)行在服務(wù)器端模式下的HotSpot虛擬機(jī)陵珍,很重要的原因是:除了Serial收集器之外,目前只有它能與CMS收集器配合工作违施,ParNew默認(rèn)開啟的收集線程數(shù)與處理器核心數(shù)量相同互纯,可以通過-XX:ParallelGCThreads參數(shù)來限制垃圾收集的線程數(shù)。
CMS收集器是HotSpot虛擬機(jī)中第一款真正意義上支持并發(fā)的垃圾收集器磕蒲,它首次實(shí)現(xiàn)了讓垃圾收集線程與用戶線程同時(shí)工作留潦。
ParNew收集器是激活CMS后的默認(rèn)新生代收集器收苏,使用-XX:+UseConcMarkSweepGC選項(xiàng)。
Parallel Scavenge收集器
Parallel Scavenge表面上看與ParNew非常相似愤兵,同樣是一款新生代收集器鹿霸,基于標(biāo)記——復(fù)制算法實(shí)現(xiàn)的收集器,能夠并行收集的多線程收集器秆乳。
但是懦鼠,Parallel Scavenge收集器的目標(biāo)則是達(dá)到一個(gè)可控制的吞吐量。
吞吐量 = 運(yùn)行用戶代碼時(shí)間 / (運(yùn)行用戶代碼時(shí)間 + 運(yùn)行垃圾代碼時(shí)間)
Serial Old 收集器
Serial Old是Serial收集器的老年代版本屹堰,它同樣是一個(gè)單線程收集器肛冶,使用標(biāo)記——整理算法。
Parallel Old收集器
Parallel Old是Parallel Scavenge收集器的老年代版本扯键,支持多線程并發(fā)收集睦袖,基于標(biāo)記——整理算法實(shí)現(xiàn)。
直到Parallel Old出現(xiàn)后荣刑,“吞吐量?jī)?yōu)先”收集器終于有了名副其實(shí)的搭配組合馅笙,在注重吞吐量或者處理器資源較為稀缺的場(chǎng)合,都可以優(yōu)先考慮Parallel Scavenge加Parallel Old收集器這個(gè)組合厉亏。
CMS收集器
CMS(Concurrent Mark Sweep)收集器是一種以獲取最短回收停頓時(shí)間為目標(biāo)的收集器董习。目前很多Java應(yīng)用集中在互聯(lián)網(wǎng)網(wǎng)站或基于瀏覽器的B/S系統(tǒng)的服務(wù)端上,這類應(yīng)用通常都較為關(guān)注服務(wù)的響應(yīng)速度爱只,希望系統(tǒng)停頓時(shí)間盡可能短皿淋,給用戶帶來良好的交互體驗(yàn)。
CMS收集器整個(gè)過程分為四個(gè)步驟:
1恬试、初始標(biāo)記
2窝趣、并發(fā)標(biāo)記
3、重新標(biāo)記
4训柴、并發(fā)清除
在初始標(biāo)記哑舒、重新標(biāo)記這兩個(gè)步驟仍然需要“Stop The World”。
初始標(biāo)記僅僅標(biāo)記一下GC Roots能直接關(guān)聯(lián)到的對(duì)象畦粮,速度很快散址;
并發(fā)標(biāo)記是從GC Roots的直接關(guān)聯(lián)對(duì)象開始遍歷整個(gè)對(duì)象圖的過程,這個(gè)過程畢竟耗時(shí)但是不需要停頓用戶線程宣赔,可以與垃圾收集線程一起并發(fā)運(yùn)行预麸;
重新標(biāo)記是為了修正并發(fā)標(biāo)記期間,因用戶程序繼續(xù)運(yùn)行而導(dǎo)致標(biāo)記產(chǎn)生變化的那部分對(duì)象的標(biāo)記記錄(增量更新)儒将,這個(gè)階段耗時(shí)比初始階段稍長(zhǎng)吏祸,比并發(fā)階段稍短;
并發(fā)清除階段钩蚊,清理刪除掉標(biāo)記階段判斷的已經(jīng)死亡的對(duì)象贡翘,這個(gè)階段也是可以和用戶線程同時(shí)并發(fā)的蹈矮。
Garbage First 收集器
Garbage First(G1)收集器是垃圾收集器技術(shù)發(fā)展歷史上的里程碑的成果,它開創(chuàng)了收集器面向局部收集的設(shè)計(jì)思路和基于Region的內(nèi)存布局形式鸣驱。
G1不在堅(jiān)持固定大小以及固定數(shù)量的分代區(qū)域劃分泛鸟,而是把連續(xù)的Java堆劃分為多個(gè)大小相等的對(duì)立區(qū)域(Region),每個(gè)區(qū)域都可以根據(jù)需要踊东,扮演新生代的Eden空間北滥、Survivor空間或者老年代空間。
收集器能夠堆扮演不同角色的Region采用不同的策略去處理闸翅。
G1收集器運(yùn)行的四個(gè)步驟:
1再芋、初始標(biāo)記:只是標(biāo)記一下GC Roots能直接關(guān)聯(lián)到的對(duì)象,并且修改TAMS指針的值坚冀,讓下一階段用戶線程并發(fā)運(yùn)行時(shí)济赎,能正確的在可用的Region中分配新對(duì)象。這個(gè)階段需要停頓線程记某,但耗時(shí)短司训。
2、并發(fā)標(biāo)記:從GC Roots開始對(duì)堆對(duì)象進(jìn)行可達(dá)性分析辙纬,遞歸掃描整個(gè)堆的對(duì)象圖豁遭,找出要回收的對(duì)象叭喜,這階段耗時(shí)較長(zhǎng)贺拣,可與用戶程序并發(fā)執(zhí)行。當(dāng)對(duì)象圖掃描完捂蕴,還要重新處理SATB記錄下的在并發(fā)時(shí)有引用變動(dòng)的對(duì)象譬涡。
3、最終標(biāo)記:對(duì)用戶線程做另一個(gè)短暫的暫停啥辨,用于處理并發(fā)階段結(jié)束后仍遺留下來的最后那少量的SATB記錄涡匀。
4、篩選回收:負(fù)責(zé)更新Region的統(tǒng)計(jì)數(shù)據(jù)溉知,對(duì)各個(gè)Region的回收價(jià)值和成本進(jìn)行排序陨瘩,根據(jù)用戶所期望的停頓時(shí)間來制定回收計(jì)劃,可以自由選擇任意多個(gè)Region構(gòu)成回收集级乍,然后把決定回收的那一部分Region的存活對(duì)象復(fù)制到空的Region中舌劳,再清理掉整個(gè)舊的Region的全部空間。