//FIX
這里主要向大家介紹目前HostSpot虛擬機中有哪些垃圾收集器,各自的特點耻蛇。并分析各個垃圾收集的使用場景。
目前還沒有哪一種收集器是萬能的议经,只能說哪種收集器更適用哪些場景洁墙。
1. Serial收集器
Serial(串行)收集器是最先出現(xiàn)的收集器卷扮。這是一個單線程的收集器盗舰,并且在收集的過程中會暫停其他工作線程庭瑰,直到收集結(jié)束。這種在垃圾收集的時候暫停其他一切工作線程的情況叫做“Stop the World”危喉,這種暫停一切工作線程對于很多應(yīng)用是難以接受的宋渔,比如你使用一個應(yīng)用,每用1小時就要暫停幾分鐘辜限,這對于用戶體驗是非常糟糕的皇拣。所以我們要盡量減少出現(xiàn)這種“Stop the World”的情況。
對于“Stop the World”有一個很形象的比喻:程序在堆或者方法區(qū)中創(chuàng)建對象相當于你在屋子里制造垃圾薄嫡,而垃圾收集器就相當于有一個保姆在給你打掃垃圾氧急。在打掃垃圾的時候你還在往地上亂扔垃圾,這房間就很難打掃完毫深。(一般懶的人會說我家在打掃屋子的時候就是一邊打掃一邊扔啊吩坝,這種后面會有講到怎么讓你一邊扔垃圾一邊打掃)
雖然這種比喻不是很準確,但“Stop the world”就是在讓你不要在修改對象之間的引用了哑蔫。
目前只有在Client模式下會默認是新生代收集器钉寝。雖然使用這種收集器會出現(xiàn)長時間的停頓,但相比于其他的收集器也有其優(yōu)點鸳址,那就是可以專注于一件事情瘩蚪,沒有切換線程的開銷。在桌面應(yīng)用程序的場景中稿黍,分配給虛擬機管理的內(nèi)存通常來說不會很多疹瘦。一般就幾十兆或者說在多一點一兩百兆的新生代。只要停頓時間可以控制在幾十毫秒或者一百多毫秒以內(nèi)的話巡球,這點停頓是可以接受的言沐。(在平時玩游戲的延遲都會在幾十毫秒以內(nèi),這樣對于玩家是完全可以接受的酣栈,同理對于幾十毫秒的停頓對于用戶來說也是一樣)所以险胰,Serial收集器對于在Client模式下的虛擬機來說是一個很好的選擇。
2.ParNew收集器
簡單來說ParNew收集器就是Serial收集器的多線程版本矿筝。
ParNew收集器沒有什么創(chuàng)新之處起便,但它卻是許多Server模式下的首選的新生代收集器,其中有一個很重要的原因就是目前還有他能和CMS收集器配合工作窖维。(CMS收集器是一款具有跨時代意義的垃圾收集器榆综,稍后會做介紹)目前CMS作為年老代的收集器,新生代只能選擇Serial收集器或者是ParNew收集器铸史。
由于ParNew收集器是多線程的鼻疮,所以現(xiàn)在單CPU的服務(wù)器上是沒有Serial收集器的效果好的,但是隨著CPU數(shù)量的提升琳轿,ParNew收集器的優(yōu)勢就會體現(xiàn)出來了判沟。ParNew收集器默認開啟的收集線程數(shù)是和CPU的數(shù)量是相同的耿芹,我們也可用-XX:ParallelGCThreads這個參數(shù)來制定線程數(shù)。
3. Parallel Scavenge 收集器
也是一個新生代收集器挪哄,也是使用的復(fù)制算法吧秕,也是并行的多線程收集器。中燥。寇甸。那么它有什么特別之處呢?
它的特點是它的關(guān)注點和其他收集器不同疗涉,其他的收集器都要盡量的縮短垃圾回收的停頓時間,而Parallel Scavenge收集器則是希望到達一個可以控制的吞吐量吟秩。在垃圾收集的過程中吞吐量是指:用戶運行代碼時間/(運行代碼時間+垃圾收集時間)咱扣。
停頓時間短適合那些需要和用戶交互的程序,然而吞吐量高的則是合適那些在后臺運算不需要太多交互的程序涵防。
Parallel Scavenge提供了兩個參數(shù)來控制吞吐量闹伪,一個是最大垃圾回收停頓時間-XX:MaxGCPauseMillis和吞吐量大小-XX:GCTimeRatio參數(shù)。ParallelScavenge收集器會盡量滿足你設(shè)置的這兩個值壮池。
Parallel Scavenge收集器有一個很重要的參數(shù)是:-XX:+UseAdaptiveSizePolicy偏瓤。這是一個開關(guān)參數(shù),如果打開之后椰憋,就不需要你自己配置新生代大小厅克,Eden區(qū)大小和Survivor區(qū)大小和晉升老年代年齡等參數(shù)了。收集器會根據(jù)你虛擬機實際運行情況來自行調(diào)整橙依,以找到適合的最大吞吐量或者是停頓時間证舟。
4. Serial Old 收集器
就是Serial老年代版本,單線程窗骑,使用標記-整理算法女责。
5. Parallel Old 收集器
Parallel Old 是Parallel Scavenge收集器的老年代版本,使用的是標記整理算法创译,多線程抵知。在JDK1.6中才開始提供的。在此之前如果年輕代用了Parallel Scavenge收集器软族,那么在老年代中只能使用Serial Old收集器刷喜。這樣的組合在多核CPU上的吞吐量未必能有ParNew+CMS組合給力。
在Parallel Old收集器出現(xiàn)后互订,在吞吐量優(yōu)先上就可以優(yōu)先考慮Parallel組合的收集器了吱肌。
6. CMS收集器
CMS(Concurrent Mark Sweep)收集器是一種哦以獲取最短回收停頓時間為目標的收集器。最使用的場景就是Java的B/S系統(tǒng)的服務(wù)器上仰禽。B/S架構(gòu)的程序尤其要重視服務(wù)器的響應(yīng)速度氮墨,相應(yīng)速度越短則用戶體驗就越好纺蛆。
CMS是基于標記-清除算法的,它的收集過程相對復(fù)雜一些规揪,主要分四個步驟:
- 初始標記:僅僅是標記一下GC Roots能直接關(guān)聯(lián)到的對象桥氏。速度很快。
- 并發(fā)標記:通過GC Roots來遍歷對象的過程猛铅。這段期間是允許用戶程序繼續(xù)運行的字支。
- 重新標記:修正并發(fā)標記期間因用戶程序運行而導(dǎo)致變動的那一部分標記記錄。
- 并發(fā)清除:就是對沒有被引用的對象進行清除奸忽。
首先堕伪,執(zhí)行最長時間的是并發(fā)標記和并發(fā)清除這兩個階段,由于這兩個階段都是可以和用戶程序一起執(zhí)行的栗菜。雖然在初始標記和重新標記期間還是需要“Stop The World”欠雌。但這兩個階段都是很快的,總體來說CMS收集器是一個低停頓的收集器疙筹。
但CMS收集器也有它的缺點:
- 第一個缺點是CMS收集器很依賴CPU資源富俄。CMS默認啟動的回收線程數(shù)是(CPU數(shù)量+3)/ 4,那么在CPU在4個以上的時候需要占用四分之一以上的CPU資源而咆,CPU越多占用的就越少霍比。但如果CPU數(shù)量就兩個的話就會占用一般的CPU資源,這是讓人無法接受的暴备。
- CMS收集器可能會出現(xiàn)“Concurrent Mode Failure”錯誤悠瞬,而導(dǎo)致產(chǎn)生一次Full GC。這是由于在并發(fā)清理階段用戶程序還在運行馍驯,這時候產(chǎn)生的垃圾就無法被清除掉阁危,只好留給下一次GC的時候在清除掉。如果是用戶程序產(chǎn)生的垃圾速度要更快一些汰瘫,導(dǎo)致要填滿了老年代狂打,那么用戶的程序就因為沒有內(nèi)存而無法運行了。所以在CMS收集器中需要預(yù)留一部分空間來當做并發(fā)收集時程序所使用的混弥。在JDK1.5的時候是當老年代使用超過了68%就會進行回收趴乡。在1.6中CMS收集器啟動的閥值默認已經(jīng)提升至92%了。如果預(yù)留的不夠了就會出現(xiàn)“Concurrent Mode Failure”錯誤蝗拿。這時候虛擬機就會啟動預(yù)備方案晾捏,使用Serial Old收集器來進行老年代的回收。這樣停頓的時間就變長了哀托。
- 第三個缺點就是CMS是基于“標記-清除”來實現(xiàn)的惦辛。所以在清除的時候會產(chǎn)生大量的內(nèi)存碎片,給分配大對象帶來了很大的麻煩仓手。如果無法分配一個大對象就不得不進行一次Full GC胖齐。為了這個缺點玻淑,設(shè)計者提供了一個參數(shù),來設(shè)置執(zhí)行多少次不壓縮的Full GC后跟著來一次壓縮的GC呀伙。