面試官:說一下JVM常用垃圾回收器的特點(diǎn)、優(yōu)劣勢、使用場景和參數(shù)設(shè)置
Java中的垃圾回收器幾乎是面試中的必考點(diǎn),無論是面試初級,中級還是高級,總免不了要問一問垃圾回收器的一些知識點(diǎn)。不管在實(shí)際開發(fā)中你使用程度怎么樣,為了面試不被壓價(jià),還是非常有必要對它做一個(gè)較深入的理解。
本篇對JVM中常用的幾種垃圾回收器的主要特點(diǎn),使用場景及優(yōu)化建議做一個(gè)簡單介紹,希望起到拋磚引玉的效果,對你入門有所幫助。
新生代回收器
- Serial
- ParNew
- parallel
老年代回收器
- Serial Old
- CMS
- Parallel Old
新生代和老年代回收器
- G1
Serial
特點(diǎn)
Serial收集器是最基本、發(fā)展歷史最悠久的收集器。JDK1.3.1前是HotSpot新生代收集的唯一選擇。
運(yùn)行示意圖
有如下特點(diǎn):
- 針對新生代;
- 采用復(fù)制算法;
- 單線程收集;
- 進(jìn)行垃圾收集時(shí),必須暫停所有工作線程,直到完成;
優(yōu)勢:
簡單高效,由于采用的是單線程的方法,因此與其他類型的收集器相比,對單個(gè)cpu來說沒有了上下文之間的的切換,效率比較高。
劣勢:
會(huì)在用戶不知道的情況下停止所有工作線程。
使用場景
- Client 模式(桌面應(yīng)用)
在用戶的桌面應(yīng)用場景中,可用內(nèi)存一般不大,可以在較短時(shí)間內(nèi)完成垃圾收集,只要不頻繁發(fā)生,這是可以接受的
- 單核服務(wù)器
對于限定單個(gè)CPU的環(huán)境來說,Serial收集器沒有線程切換開銷,可以獲得最高的單線程收集效率
參數(shù)設(shè)置
- -XX:+UseSerialGC:添加該參數(shù)來顯式的使用串行垃圾收集器
ParNew
特點(diǎn)
ParNew收集器其實(shí)就是Serial收集器的多線程版本,除了使用多線程進(jìn)行垃圾收集之外,其余均和Serial 收集器一致。
運(yùn)行示意圖
優(yōu)勢:
多線程版本的Serial,可以更加有效的利用系統(tǒng)資源
劣勢:
同Serial,會(huì)在用戶不知道的情況下停止所有工作線程
使用場景
Server模式下使用,亮點(diǎn)是除Serial外,目前只有它能與CMS收集器配合工作,是一個(gè)非常重要的垃圾回收器。
參數(shù)設(shè)置
- -XX:+UseConcMarkSweepGC:指定使用CMS后,會(huì)默認(rèn)使用ParNew作為新生代收集器;
- -XX:+UseParNewGC:強(qiáng)制指定使用ParNew;
- -XX:ParallelGCThreads:指定垃圾收集的線程數(shù)量,ParNew默認(rèn)開啟的收集線程與CPU的數(shù)量相同;
parallel
特點(diǎn)
Parallel Scavenge也是一款用于新生代的多線程收集器,也是采用復(fù)制算法。與ParNew的不同之處在于Parallel Scavenge收集器的目的是達(dá)到一個(gè)可控制的吞吐量,而ParNew收集器關(guān)注點(diǎn)在于盡可能的縮短垃圾收集時(shí)用戶線程的停頓時(shí)間。
運(yùn)行示意圖
有如下特點(diǎn):
- 新生代收集器;
- 采用復(fù)制算法;
- 多線程收集;
- 關(guān)注點(diǎn)與其他收集器不同:
- CMS等收集器的關(guān)注點(diǎn)是盡可能地縮短垃圾收集時(shí)用戶線程的停頓時(shí)間;
- 而Parallel Scavenge收集器的目標(biāo)則是達(dá)一個(gè)可控制的吞吐量;
優(yōu)勢:
追求高吞吐量,高效利用CPU,是吞吐量優(yōu)先,且能進(jìn)行精確控制。
劣勢:
應(yīng)該說是特點(diǎn),追求高吞吐量必然要犧牲一些其他方面的優(yōu)勢,不能做到既,又。ParNew收集器關(guān)注點(diǎn)在于盡可能的縮短垃圾收集時(shí)用戶線程的停頓時(shí)間,原本10s收集一次, 每次停頓100ms, 設(shè)置完參數(shù)之后可能變成5s收集一次, 每次停頓70ms. 停頓時(shí)間變短, 但收集次數(shù)變多。
使用場景
根據(jù)相關(guān)特性,我們很容易想到它的使用場景,即:當(dāng)應(yīng)用程序運(yùn)行在具有多個(gè)CPU上,對暫停時(shí)間沒有特別高的要求時(shí),程序主要在后臺(tái)進(jìn)行計(jì)算,而不需要與用戶進(jìn)行太多交互等就特別適合ParNew收集器。
- 例如,那些執(zhí)行批量處理、訂單處理、工資支付、科學(xué)計(jì)算的應(yīng)用程序等
參數(shù)設(shè)置
- -XX:MaxGCPauseMillis:控制最大垃圾收集停頓時(shí)間,大于0的毫秒數(shù);
- -XX:GCTimeRatio:設(shè)置垃圾收集時(shí)間占總時(shí)間的比率,0<n<100的整數(shù);
Serial Old
特點(diǎn)
Serial Old是Serial收集器的老年代版本,同樣是一個(gè)單線程收集器,使用標(biāo)記-整理算法。
有如下特點(diǎn):
- 針對老年代;
- 采用"標(biāo)記-整理"算法(還有壓縮,Mark-Sweep-Compact);
- 單線程收集;
優(yōu)劣勢基本和Serial無異,它是和Serial收集器配合使用的老年代收集器。
使用場景
- Client模式;
- 單核服務(wù)器;
- 與Parallel Scavenge收集器搭配;
- 作為CMS收集器的后備方案,在并發(fā)收集發(fā)生Concurrent Mode Failure時(shí)使用
CMS
特點(diǎn)
CMS(Concurrent Mark Sweep)收集器是一種以獲取最短回收停頓時(shí)間為目標(biāo)的收集器。采用的算法是“標(biāo)記-清除”,運(yùn)作過程分為四個(gè)步驟:
- 初始標(biāo)記,標(biāo)記GC Roots 能夠直接關(guān)聯(lián)到達(dá)對象
- 并發(fā)標(biāo)記,進(jìn)行GC Roots Tracing 的過程
- 重新標(biāo)記,修正并發(fā)標(biāo)記期間因用戶程序繼續(xù)運(yùn)作而導(dǎo)致標(biāo)記產(chǎn)生變動(dòng)的那一部分標(biāo)記記錄
- 并發(fā)清除,用標(biāo)記清除算法清除對象。
運(yùn)行示意圖
有如下特點(diǎn):
- 針對老年代;
- 基于"標(biāo)記-清除"算法(不進(jìn)行壓縮操作,產(chǎn)生內(nèi)存碎片);
- 以獲取最短回收停頓時(shí)間為目標(biāo);
- 并發(fā)收集、低停頓;
- 需要更多的內(nèi)存(看后面的缺點(diǎn));
優(yōu)勢:
- 停頓時(shí)間短;
- 吞吐量大;
- 并發(fā)收集
劣勢:
- 對CPU資源非常敏感
- 無法收集浮動(dòng)垃圾
- 容易產(chǎn)生大量內(nèi)存碎片
使用場景
- 與用戶交互較多的場景;
- 希望系統(tǒng)停頓時(shí)間最短,注重服務(wù)的響應(yīng)速度;
- 以給用戶帶來較好的體驗(yàn);
如常見WEB、B/S系統(tǒng)的服務(wù)器上的應(yīng)用。
參數(shù)設(shè)置
- -XX:+UseConcMarkSweepGC:指定使用CMS收集器
Parallel Old
特點(diǎn)
Parallel Old是Parallel Scavenge收集器的老年代版本,使用多線程和“標(biāo)記-整理”算法,可以充分利用多核CPU的計(jì)算能力。
有如下特點(diǎn):
- 針對老年代;
- 采用"標(biāo)記-整理"算法;
- 多線程收集;
優(yōu)劣勢參考Parallel Scavenge收集器。
使用場景
- JDK1.6及之后用來代替老年代的Serial Old收集器;
- 特別是在Server模式,多CPU的情況下;
這樣在注重吞吐量以及CPU資源敏感的場景,就有了Parallel Scavenge(新生代)加Parallel Old(老年代)收集器的"給力"應(yīng)用組合;
參數(shù)設(shè)置
- -XX:+UseParallelOldGC:指定使用Parallel Old收集器
G1
特點(diǎn)
G1(Garbage-First)是JDK7-u4才推出商用的收集器
- 并行與并發(fā):G1能充分利用多CPU,多核環(huán)境下的硬件優(yōu)勢。
- 分代收集:能夠采用不同的方式去處理新創(chuàng)建的對象和已經(jīng)存活了一段時(shí)間的對象,不需要與其他收集器進(jìn)行合作。
- 空間整合:G1從整體上來看基于“標(biāo)記-整理”算法實(shí)現(xiàn)的收集器,從局部上看是基于復(fù)制算法實(shí)現(xiàn)的,因此G1運(yùn)行期間不會(huì)產(chǎn)生空間碎片。
- 可預(yù)測的停頓:G1能建立可預(yù)測的時(shí)間停頓模型,能讓使用者明確指定一個(gè)長度為M毫秒的時(shí)間片段內(nèi),消耗在垃圾收集上的時(shí)間不得超過N毫秒。
運(yùn)行示意圖
有如下特點(diǎn):
- 并行與并發(fā)
- 分代收集,收集范圍包括新生代和老年代
- 結(jié)合多種垃圾收集算法,空間整合,不產(chǎn)生碎片
- 可預(yù)測的停頓:低停頓的同時(shí)實(shí)現(xiàn)高吞吐量
- 面向服務(wù)端應(yīng)用,將來替換CMS
優(yōu)勢:
- 能充分利用多CPU、多核環(huán)境下的硬件優(yōu)勢;
- 能獨(dú)立管理整個(gè)GC堆(新生代和老年代),而不需要與其他收集器搭配;
- 不會(huì)產(chǎn)生內(nèi)存碎片,有利于長時(shí)間運(yùn)行;
- 除了追求低停頓處,還能建立可預(yù)測的停頓時(shí)間模型;
G1收集器是當(dāng)今收集器技術(shù)發(fā)展的最前沿成果。
劣勢:
G1 需要記憶集 (具體來說是卡表)來記錄新生代和老年代之間的引用關(guān)系,這種數(shù)據(jù)結(jié)構(gòu)在 G1 中需要占用大量的內(nèi)存,可能達(dá)到整個(gè)堆內(nèi)存容量的 20% 甚至更多。而且 G1 中維護(hù)記憶集的成本較高,帶來了更高的執(zhí)行負(fù)載,影響效率。
按照《深入理解Java虛擬機(jī)》作者的說法,CMS 在小內(nèi)存應(yīng)用上的表現(xiàn)要優(yōu)于 G1,而大內(nèi)存應(yīng)用上 G1 更有優(yōu)勢,大小內(nèi)存的界限是6GB到8GB。
所以,盡管是最前沿的成果,也不是完美無缺的。
使用場景
個(gè)人以為G1已經(jīng)基本全面壓制cms、parallel等回收器,缺點(diǎn)見上面的劣勢。但如果不是追求極致的性能,基本可以無腦G1
參數(shù)設(shè)置
- -XX:+UseG1GC:指定使用G1收集器;
- -XX:InitiatingHeapOccupancyPercent:當(dāng)整個(gè)Java堆的占用率達(dá)到參數(shù)值時(shí),開始并發(fā)標(biāo)記階段;默認(rèn)為45;
- -XX:MaxGCPauseMillis:為G1設(shè)置暫停時(shí)間目標(biāo),默認(rèn)值為200毫秒;
- -XX:G1HeapRegionSize:設(shè)置每個(gè)Region大小,范圍1MB到32MB;目標(biāo)是在最小Java堆時(shí)可以擁有約2048個(gè)Region;
基本就介紹這些了,垃圾回收器基本不變的知識點(diǎn)多,學(xué)會(huì)(理解)可以應(yīng)付N年的相關(guān)知識的面試,又是高頻面試考點(diǎn),各位同學(xué)還是值得在這塊下點(diǎn)功夫的。文中有任何不足,錯(cuò)誤歡迎指出,共同進(jìn)步!