目錄
- 概述
- 新生代GC
- 老年代GC
- java789默認(rèn)GC搭配
- 垃圾收集器相關(guān)參數(shù)總結(jié)
概述
整理歸納HotSpot中的GC收集器相關(guān)性能,算法使用货裹,GC過程和相互搭配。需要先明確一個觀點(diǎn):GC收集器根本上來說沒有絕對的優(yōu)劣,我們只能根據(jù)具體場景選擇最適合的GC組合恩伺,而不是選擇一個完美的GC組合。
介紹之前椰拒,先需要了解兩個名詞概念:
- 并行:多條GC線程并行工作晶渠,此時用戶線程仍處于停頓狀態(tài)
-
并發(fā):用戶線程與垃圾收集線程同時執(zhí)行(并行或交替執(zhí)行)
新生代GC
Serial收集器
- 單線程
單線程有兩個方面含義:一方面凰荚,serial收集器只使用一個CPU或一條收集線程進(jìn)行GC;另一方面褒脯,serial進(jìn)行GC時便瑟,需要暫停其他所有的工作線程直到垃圾回收結(jié)束(Stop The World)
一方面,Serial收集器只是用一條GC線程去執(zhí)行收集任務(wù)憨颠;另一方面胳徽,Serial收集器進(jìn)行收集時,必須暫停其他所有的工作線程(Stop The World)爽彤,直到收集結(jié)束养盗。
- 新生代采用復(fù)制算法;老年代采用標(biāo)記-整理算法
-
Client模式下默認(rèn)新生代收集器适篙,能與CMS搭配使用
ParNew收集器
- 多線程GC往核,采用多線程進(jìn)行收集工作
- Server模式下的虛擬機(jī)中首選的新生代收集器,能與CMS搭配使用
- 除多線程GC外嚷节,其余參數(shù)包括Serial收集器可用的所有控制參數(shù)聂儒、Stop The World、收集算法硫痰、對象分配規(guī)則衩婚、回收策略都與Serial完全一樣
Parallel Scavenge收集器
- 多線程并行GC
- 新生代采用復(fù)制算法;老年代采用標(biāo)記-清除算法
- 關(guān)注吞吐量
- GC自適應(yīng)調(diào)節(jié)策略
吞吐量 = 運(yùn)行用戶代碼時間 / (運(yùn)行用戶代碼時間 + 垃圾收集時間)
CMS等收集器關(guān)注點(diǎn)是盡可能縮短垃圾收集時用戶線程停頓的時間效斑,Parallel Scavenge收集器關(guān)注的是達(dá)到一個可觀的吞吐量非春。
停頓時間短適合需要和用戶交互多的程序;高吞吐量可以高效利用CPU使用率缓屠,適合在后臺運(yùn)算而不需要太多交互的任務(wù)奇昙。
Parallel Scavenge收集器提供兩個參數(shù)用于控制吞吐量:
-XX:MaxGCPauseMillis :最大垃圾收集停頓時間。值與新生代空間和吞吐量成反比敌完。
-XX:GCTimeRatio:吞吐量大小储耐。值可以理解為正常運(yùn)行時間相對垃圾收集時間的倍數(shù),即正常運(yùn)行時間/垃圾回收時間滨溉,默認(rèn)值為99什湘,即允許最大1%(1/1+99)的垃圾收集時間。
GC自適應(yīng)調(diào)節(jié)策略:
Parallel Scavenge收集器還有一個參數(shù)-XX:+UseAdaptiveSizePolicy設(shè)置當(dāng)前系統(tǒng)是否使用自適性系統(tǒng)參數(shù)調(diào)節(jié)业踏,當(dāng)開關(guān)打開時禽炬,系統(tǒng)不需要手動設(shè)置新生代大小、Eden和Survivor比例勤家、晉升老年代對象年齡腹尖。
老年代GC
Serial Old收集器
- Serial收集器老年代版本
- 單線程
- 標(biāo)記-整理算法
- JDK1.5 以及以前的版本中與 Parallel Scavenge 收集器搭配使用
- CMS收集器備用預(yù)案,在CMS發(fā)生“Concurrent Mode Failure”時使用
Parallel Old收集器
- Parallel Scavenge收集器老年代版本,與Parallel Scavenge收集器搭配热幔,構(gòu)成“名副其實(shí)”的“吞吐量優(yōu)先”收集器
- 多線程并行GC
- 標(biāo)記-整理算法
CMS(Concurrent Mark Sweep)收集器
HotSpot第一款真正意義上的并發(fā)收集器乐设。第一次實(shí)現(xiàn)了GC線程和工作線程(基本上)同時工作
收集過程
- 初始標(biāo)記
- 并發(fā)標(biāo)記
- 重復(fù)標(biāo)記
- 并發(fā)清除
初始標(biāo)記
只標(biāo)記GC Roots能直接關(guān)聯(lián)到的對象,需要Stop The World(STW)绎巨。
并發(fā)標(biāo)記
進(jìn)行GC Roots引用鏈追蹤近尚,標(biāo)記所有有關(guān)聯(lián)的對象。這時GC線程能和用戶線程同時工作(用書上的形容是:真正的實(shí)現(xiàn)了你邊丟垃圾场勤,你媽媽邊打掃衛(wèi)生)戈锻。
重復(fù)標(biāo)記
修正并發(fā)標(biāo)記時,發(fā)生引用關(guān)系變化的那部分對象的引用和媳,需要Stop The World格遭。
并發(fā)清除
使用并發(fā)-清除算法對垃圾對象進(jìn)行清除。
并發(fā)重置
CMS清除內(nèi)部狀態(tài)留瞳,為下次GC做準(zhǔn)備
評價
- 并發(fā)收集拒迅、低停頓
整個過程中耗時最長的并發(fā)標(biāo)記和并發(fā)清除過程收集器線程都可以與用戶線程一起工作,所以她倘,從總體上來說璧微,CMS收集器的內(nèi)存回收過程是與用戶線程一起并發(fā)執(zhí)行的 - 并發(fā)-清除算法
不足
-
與用戶線程爭奪CPU資源
雖然并發(fā)標(biāo)記和并發(fā)清除時硬梁,不會導(dǎo)致用戶線程停頓,但由于占用一部分線程資源而導(dǎo)致應(yīng)用程序速度變慢荧止。CMS默認(rèn)啟動的回收線程是(CPU數(shù)量 + 3) / 4 -
無法處理浮動垃圾
CMS收集器進(jìn)行到并發(fā)清除階段時,由于并發(fā)執(zhí)行罩息,系統(tǒng)仍然會產(chǎn)生一些垃圾个扰,這些垃圾產(chǎn)生在標(biāo)記之后,所以需要等待下次GC再清除他們递宅,這些垃圾叫做“浮動垃圾”娘香。正因如此,CMS收集器對老年代需要預(yù)留一部分空間提供并發(fā)收集時的程序運(yùn)作使用办龄。
CMS通過設(shè)置參數(shù)(-XX:CMSInitiatingOccupancyFraction)用來表示老年代使用多少空間時烘绽,激活CMS。設(shè)置這個參數(shù)需要有兩方面的考量:一方面俐填,當(dāng)參數(shù)值設(shè)置過低安接,觸發(fā)CMS的GC次數(shù)會變多,降低性能英融;另一方面盏檐,當(dāng)參數(shù)值設(shè)置過高歇式,剩余空間不足以存儲產(chǎn)生的浮動垃圾,系統(tǒng)會報“Concurrent Mode Failure”胡野,系統(tǒng)將啟動預(yù)備方案:使用Serial Old收集器進(jìn)行老年代的垃圾收集材失,這樣導(dǎo)致耗時更多,影響性能硫豆。 -
并發(fā)-清除算法產(chǎn)生大量空間碎片
并發(fā)-清除算法將產(chǎn)生大量空間碎片龙巨,當(dāng)大對象進(jìn)入內(nèi)存時,會由于沒有足夠的連續(xù)內(nèi)存空間分配而提前觸發(fā)Full GC熊响。
為此設(shè)計者提供了兩個參數(shù)旨别。-XX:+UseCMSCompactAtFullCollection開關(guān)參數(shù)控制CMS收集器在需要進(jìn)行Full GC時,是否開啟內(nèi)存碎片整理過程(默認(rèn)是開啟的)耘眨。-XX:CMSFullGCsBeforeCompaction設(shè)置執(zhí)行多少次不壓縮內(nèi)存空間的Full GC后昼榛,進(jìn)行一次帶壓縮的Full GC(默認(rèn)為0,即每次進(jìn)入Full GC都要進(jìn)行碎片整理)剔难。
G1收集器
代替Parallel Scavenge和Parallel Old組合收集器胆屿,成為JDK1.9服務(wù)端模式下默認(rèn)垃圾收集器。設(shè)計初衷是建立起“停頓時間模型”的收集器偶宫,即支持指定在一個長度為M毫秒的時間片段內(nèi)非迹,消耗在GC上的時間不超過N毫秒這樣的目標(biāo)。
簡述
- 可預(yù)測的停頓
- 分代收集
- 并發(fā)
- 標(biāo)記-清除纯趋,兩個Region之間局部表現(xiàn)為標(biāo)記-復(fù)制
- Region不分代導(dǎo)致記憶集和其他內(nèi)存消耗較大憎兽。
可預(yù)測的停頓:G1支持使用者設(shè)置在M時間中停頓N秒。G1在后臺維護(hù)一個列表用于記錄每個Region里面的垃圾回收的價值(回收獲得的空間大小和回收所需時間)吵冒,根據(jù)用戶設(shè)置的時間纯命,制定回收計劃,優(yōu)先回收價值大的區(qū)域(Garbage-First的由來)亿汞。
收集思想(Mixed GC模式)
之前的垃圾收集器的垃圾收集對象為整個新生代(Minor GC)疗我、整個老年代(Major GC)或整個Java堆(Full GC)吴裤。而G1面向堆內(nèi)存的任何部分來組成回收集進(jìn)行垃圾回收溺健,衡量標(biāo)準(zhǔn)不再是內(nèi)存屬于哪個年代,而是哪塊內(nèi)存中存放的垃圾數(shù)量最多愿卒,回收收益最大潮秘。
堆內(nèi)存布局(Region枕荞、Humongous)
為了實(shí)現(xiàn)這一收集目標(biāo)躏精,G1的堆內(nèi)存布局開創(chuàng)了基于Region的堆內(nèi)存布局。
G1雖仍然遵循分代收集辅柴,但是不同于之前的收集器將年輕代碌嘀、年老代和元空間按照固定大小以及固定數(shù)量進(jìn)行區(qū)域劃分股冗,而是將連續(xù)的Java堆劃分為大小相等的若干區(qū)域——Region,每個區(qū)域根據(jù)需要可以是任何年代的對象攒霹,各個年代沒有物理連續(xù)只有邏輯上的連續(xù)催束。收集器就可以根據(jù)扮演不同年代的Region采用不同的回收策略。
除此之外,增加了一個區(qū)域——Humongous區(qū)域矫付,用于存儲巨型對象买优,如果一個對象占用空間超過Region容量的一般,G1則認(rèn)為這是一個巨型對象(Region取值范圍為1MB~32MB烘跺,應(yīng)為2的N次冪滤淳,通過-XX:G1HeapRegionSize設(shè)定)脖咐。如果一個Region裝不下一個巨型對象屁擅,則會尋找連續(xù)的Humongous分區(qū)來存儲派歌,有時為找到連續(xù)的H分區(qū)胶果,有時會觸發(fā)Full GC作谭。H區(qū)域的出現(xiàn)避免了短期存在的巨型對象對GC造成負(fù)面影響折欠。G1大多數(shù)行為把H區(qū)域當(dāng)做老年代看待锐秦。
可預(yù)測的停頓時間模型
有了新的垃圾收集思想和堆內(nèi)存布局酱床,“可預(yù)測的停頓時間模型”得以實(shí)現(xiàn):
- 追求應(yīng)付應(yīng)用的內(nèi)存分配速率而不是追求一次把Java堆收集干凈
- 每次收集時將Region作為回收最小單元扇谣,即每次回收的內(nèi)存空間都是Region的整數(shù)倍,避免了全區(qū)域收集罐寨,因此時間可控跋破。
- 收集具體思路是讓G1收集器去跟蹤各個Region里面的垃圾堆積的“價值”大小,即回收得到的空間以及回收所需時間的經(jīng)驗值毒返,然后在后臺維護(hù)一個優(yōu)先級列表劲绪,每次根據(jù)用戶設(shè)定的收集停頓時間(默認(rèn)200毫秒)優(yōu)先處理回收價值收益最大的那些Region狡恬。
收集過程
- 初始標(biāo)記
- 并發(fā)標(biāo)記
- 最終標(biāo)記
- 篩選回收
初始標(biāo)記
只標(biāo)記GC Roots能直接關(guān)聯(lián)到的對象祷安,修改TAMS指針值汇鞭,讓下個階段能正確的在可用Region中分配對象庸追。需要停頓線程淡溯,但借用Minor GC的時候同步完成咱娶,沒有額外停頓膘侮。
并發(fā)標(biāo)記
從GC Roots進(jìn)行可達(dá)性遍歷琼了,對整個Java堆的對象圖進(jìn)行掃描雕薪,找出回收對象。這個階段可以和用戶線程并發(fā)執(zhí)行盏档。還要重新處理SATB記錄下的在并發(fā)時引用有變動的對象妆丘。
最終標(biāo)記
處理并發(fā)階段后遺留下來的少量的SATB 記錄勺拣,需要短暫暫停药有。
SATB(Snapshot At The Beginning):簡單地說就是初始標(biāo)記階段和并發(fā)標(biāo)記階段標(biāo)記為活的的對象就是活的愤惰。然后并發(fā)標(biāo)記階段新增或者引用重新執(zhí)行的對象也認(rèn)為是活的宦言。其他的就是死的
篩選回收
更新Region統(tǒng)計數(shù)據(jù),對各Region回收價值和成本進(jìn)行排序施流,根據(jù)用戶期望停頓時間來指定回收計劃瞪醋∫埽回收過程將決定回收的那一部分Region的存活對象復(fù)制到空的Region中蚓土,然后清理掉舊的Region的全部空間蜀漆。需要停頓用戶線程确丢。
由回收過程可以看出G1并非純粹追求低延遲鲜侥,而是在延遲可控的情況下獲得盡可能高的吞吐量描函。
java789默認(rèn)GC搭配
jdk1.7 Parallel Scavenge(新生代)+Parallel Old(老年代)
jdk1.8 Parallel Scavenge(新生代)+Parallel Old(老年代)
jdk1.9 G1