一些概念
并行(Parallel)
指多條垃圾收集線程并行工作,但此時(shí)用戶(hù)線程仍然處于等待狀態(tài)悯舟。
并發(fā)(Concurrent)
指用戶(hù)線程與垃圾收集線程同時(shí)執(zhí)行(但不一定是并行的担租,可能會(huì)交替執(zhí)行),用戶(hù)程序在繼續(xù)運(yùn)行抵怎,而垃圾收集程序運(yùn)行于另一個(gè)CPU上奋救。
吞吐量
CPU用于運(yùn)行用戶(hù)代碼的時(shí)間與CPU總消耗時(shí)間的比值,即吞吐量=運(yùn)行用戶(hù)代碼時(shí)間/(運(yùn)行用戶(hù)代碼時(shí)間+垃圾收集時(shí)間)反惕。虛擬機(jī)總共運(yùn)行了100分鐘尝艘,其中垃圾收集花掉1分鐘,那吞吐量就是99%承璃。
HotSpot虛擬機(jī)的垃圾回收器
Serial
- 最基本的單線程垃圾收集器利耍。使用一個(gè)CPU或一條收集線程去執(zhí)行垃圾收集工作。
- 工作時(shí)會(huì)
Stop The World
,暫停所有用戶(hù)線程隘梨,造成卡頓程癌。適合運(yùn)行在Client模式下的虛擬機(jī)。 - 用作新生代收集器轴猎,復(fù)制算法嵌莉。
ParNew
- Serial收集器的多線程版本,和Serial的唯一區(qū)別就是使用了多條線程去垃圾收集捻脖。
- 除了Serial锐峭,只有它可以和CMS搭配使用的收集器。
- 用作新生代收集器可婶,復(fù)制算法沿癞。
Parallel Scavenge
- 用作新生代收集器,復(fù)制算法矛渴。
- 關(guān)注高吞吐量椎扬,可以高效率地利用CPU時(shí)間,盡快完成程序的運(yùn)算任務(wù)具温,主要適合在后臺(tái)運(yùn)算而不需要太多交互的任務(wù)蚕涤。
- Parallel Scavenge收集器提供了兩個(gè)參數(shù)用于精確控制吞吐量,分別是控制最大垃圾收集停頓時(shí)間的
-XX:MaxGCPauseMillis
參數(shù)以及直接設(shè)置吞吐量大小的-XX:GCTimeRatio
參數(shù)铣猩。
Serial Old
- Serial收集器的老年代版本揖铜,單線程,標(biāo)記-整理 算法达皿。
- 一般用于Client模式的虛擬機(jī)天吓。
- 當(dāng)虛擬機(jī)是Server模式時(shí),有2個(gè)用途:一種用途是在JDK 1.5以及之前的版本中與Parallel Scavenge收集器搭配使用 鳞绕,另一種用途就是作為CMS收集器的后備預(yù)案失仁,在并發(fā)收集發(fā)生Concurrent Mode Failure時(shí)使用。
Parallel Old
- Parallel Scavenge收集器的老年代版本们何,使用多線程和 標(biāo)記-整理 算法萄焦。在JDK 1.6中開(kāi)始提供。
- 在注重吞吐量的場(chǎng)合冤竹,配合Parallel Scavenge收集器使用拂封。
CMS(Concurrent Mark Sweep)
- 一種以獲取最短回收停頓時(shí)間為目標(biāo)的收集器。適合需要與用戶(hù)交互的程序鹦蠕,良好的響應(yīng)速度能提升用戶(hù)體驗(yàn)冒签。
- 基于 標(biāo)記—清除 算法。適合作為老年代收集器钟病。
- 收集過(guò)程分4步:
- 初始標(biāo)記(CMS initial mark):只是標(biāo)記一下GC Roots能直接關(guān)聯(lián)到的對(duì)象萧恕,速度很快刚梭,會(huì)
Stop The World
。 - 并發(fā)標(biāo)記(CMS concurrent mark):進(jìn)行GC Roots Tracing(可達(dá)性分析)的過(guò)程票唆。
- 重新標(biāo)記(CMS remark):會(huì)
Stop The World
朴读。為了修正并發(fā)標(biāo)記期間因用戶(hù)程序繼續(xù)運(yùn)作而導(dǎo)致標(biāo)記產(chǎn)生變動(dòng)的那一部分對(duì)象的標(biāo)記記錄,這個(gè)階段的停頓時(shí)間一般比初始標(biāo)記階段稍長(zhǎng)些走趋,但遠(yuǎn)比并發(fā)標(biāo)記的時(shí)間短衅金。 - 并發(fā)清除(CMS concurrent sweep):回收內(nèi)存。
- 初始標(biāo)記(CMS initial mark):只是標(biāo)記一下GC Roots能直接關(guān)聯(lián)到的對(duì)象萧恕,速度很快刚梭,會(huì)
- 耗時(shí)最長(zhǎng)的并發(fā)標(biāo)記和并發(fā)清除過(guò)程收集器線程都可以與用戶(hù)線程一起工作簿煌,所以時(shí)并發(fā)執(zhí)行的氮唯。
- 缺點(diǎn):
- 并發(fā)階段,雖然不會(huì)導(dǎo)致用戶(hù)線程暫停姨伟,但會(huì)占用一部分線程(CPU資源)惩琉,導(dǎo)致應(yīng)用變慢,吞吐量降低授滓。默認(rèn)啟動(dòng)收集線程數(shù)是(CPU數(shù)量+3)/4琳水。即當(dāng)CPU在4個(gè)以上時(shí),并發(fā)回收時(shí)垃圾收集線程不少于25%的CPU資源般堆,并且隨著CPU數(shù)量的增加而下降。但是當(dāng)CPU不足4個(gè)(譬如2個(gè))時(shí)诚啃,CMS對(duì)用戶(hù)程序的影響就可能變得很大淮摔。
- 無(wú)法清除浮動(dòng)垃圾。并發(fā)清除階段始赎,用戶(hù)線程還在運(yùn)行和橙,還會(huì)產(chǎn)生新垃圾。這些垃圾不會(huì)在此次GC中被標(biāo)記造垛,只能等到下次GC被回收魔招。
- 標(biāo)記-清除 算法會(huì)產(chǎn)生大量不連續(xù)內(nèi)存,導(dǎo)致分配大對(duì)象時(shí)內(nèi)存不夠五辽,提前觸發(fā)Full GC办斑。
G1
在JDK1.7提供的先進(jìn)垃圾收集器。
既適合新生代杆逗,也適合老年代乡翅。
空間整合:使用 標(biāo)記-整理 算法,不產(chǎn)生碎片空間罪郊。
整個(gè)Java堆被分為多個(gè)大小相同的的塊(region)蠕蚜。新生代和老年代不再是物理隔離的,而是一部分region塊組成的集合悔橄。
可預(yù)測(cè)的停頓時(shí)間:估算每個(gè)region內(nèi)的垃圾可回收的空間以及回收需要的時(shí)間(經(jīng)驗(yàn)值)靶累,記錄在一個(gè)優(yōu)先列表中腺毫。收集時(shí),優(yōu)先回收價(jià)值最大的region挣柬,而不是在整個(gè)堆進(jìn)行全區(qū)域回收潮酒。這樣提高了回收效率,得名:Garbage-First凛忿。
-
回收步驟:
- 初始標(biāo)記(Initial Marking):只是標(biāo)記一下GC Roots能直接關(guān)聯(lián)到的對(duì)象澈灼,并且修改TAMS(Next Top at Mark Start)的值,讓下一階段用戶(hù)程序并發(fā)運(yùn)行時(shí)店溢,能在正確可用的Region中創(chuàng)建新對(duì)象叁熔,這階段需要停頓線程,但耗時(shí)很短床牧。
- 并發(fā)標(biāo)記(Concurrent Marking):進(jìn)行可達(dá)性分析荣回,找出存活對(duì)象,耗時(shí)長(zhǎng)戈咳,但可與用戶(hù)線程并發(fā)心软。
- 最終標(biāo)記(Final Marking):修正并發(fā)標(biāo)記階段用戶(hù)線程運(yùn)行導(dǎo)致的變動(dòng)記錄。會(huì)
Stop The World
著蛙,但可以并行執(zhí)行删铃,時(shí)間不會(huì)很長(zhǎng)。 - 篩選回收(Live Data Counting and Evacuation):根據(jù)每個(gè)region的回收價(jià)值和回收成本排序踏堡,根據(jù)用戶(hù)配置的GC停頓時(shí)間開(kāi)始回收猎唁。
當(dāng)內(nèi)存很少的時(shí)候(存活對(duì)象占用大量空間),沒(méi)有足夠空間來(lái)復(fù)制對(duì)象顷蟆,會(huì)導(dǎo)致回收失敗诫隅。這時(shí)會(huì)保留被移動(dòng)過(guò)的對(duì)象和沒(méi)移動(dòng)的對(duì)象,只調(diào)整引用帐偎。失敗發(fā)生后逐纬,收集器認(rèn)為存活對(duì)象被移動(dòng)了,有足夠空間讓?xiě)?yīng)用程序使用削樊,于是用戶(hù)線程繼續(xù)工作豁生,等待下一次觸發(fā)GC。如果內(nèi)存不夠嫉父,就會(huì)觸發(fā)Full GC沛硅。