HotSpot 虛擬機(jī)提供了多種垃圾收集器,每種收集器都有各自的特點(diǎn),雖然我們要對(duì)各個(gè)收集器進(jìn)行比較,但并非為了挑選出一個(gè)最好的收集器。我們選擇的只是對(duì)具體應(yīng)用最合適的收集器。
只開(kāi)啟一條GC 線程進(jìn)行垃圾回收,并且在垃圾收集過(guò)程中停止一切用戶線程,即 Stop The World。
(資料圖片)
一般客戶端應(yīng)用所需內(nèi)存較小,不會(huì)創(chuàng)建太多對(duì)象,而且堆內(nèi)存不大,因此垃圾收集器回收時(shí)間短,即使在這段時(shí)間停止一切用戶線程,也不會(huì)感覺(jué)明顯卡頓。因此 Serial 垃圾收集器適合客戶端使用。
由于 Serial 收集器只使用一條 GC 線程,避免了線程切換的開(kāi)銷,從而簡(jiǎn)單高效。
ParNew 是 Serial 的多線程版本。由多條 GC 線程并行地進(jìn)行垃圾清理。但清理過(guò)程依然需要 Stop The World。
ParNew 追求“低停頓時(shí)間”,與 Serial 唯一區(qū)別就是使用了多線程進(jìn)行垃圾收集,在多 CPU 環(huán)境下性能比 Serial 會(huì)有一定程度的提升;但線程切換需要額外的開(kāi)銷,因此在單 CPU 環(huán)境中表現(xiàn)不如 Serial。
Parallel Scavenge 和 ParNew 一樣,都是多線程、新生代垃圾收集器。但是兩者有巨大的不同點(diǎn):
Parallel Scavenge:追求 CPU 吞吐量,能夠在較短時(shí)間內(nèi)完成指定任務(wù),因此適合沒(méi)有交互的后臺(tái)計(jì)算。
ParNew:追求降低用戶停頓時(shí)間,適合交互式應(yīng)用。
吞吐量 = 運(yùn)行用戶代碼時(shí)間 / (運(yùn)行用戶代碼時(shí)間 + 垃圾收集時(shí)間)
追求高吞吐量,可以通過(guò)減少 GC 執(zhí)行實(shí)際工作的時(shí)間,然而,僅僅偶爾運(yùn)行 GC 意味著每當(dāng) GC 運(yùn)行時(shí)將有許多工作要做,因?yàn)樵诖似陂g積累在堆中的對(duì)象數(shù)量很高。單個(gè) GC 需要花更多的時(shí)間來(lái)完成,從而導(dǎo)致更高的暫停時(shí)間。而考慮到低暫停時(shí)間,最好頻繁運(yùn)行 GC 以便更快速完成,反過(guò)來(lái)又導(dǎo)致吞吐量下降。
通過(guò)參數(shù) -XX:GCTimeRadio 設(shè)置垃圾回收時(shí)間占總 CPU 時(shí)間的百分比。
通過(guò)參數(shù) -XX:MaxGCPauseMillis 設(shè)置垃圾處理過(guò)程最久停頓時(shí)間。
通過(guò)命令 -XX:+UseAdaptiveSizePolicy 開(kāi)啟自適應(yīng)策略。我們只要設(shè)置好堆的大小和 MaxGCPauseMillis 或 GCTimeRadio,收集器會(huì)自動(dòng)調(diào)整新生代的大小、Eden 和 Survivor 的比例、對(duì)象進(jìn)入老年代的年齡,以最大程度上接近我們?cè)O(shè)置的 MaxGCPauseMillis 或 GCTimeRadio。
Serial Old 收集器是 Serial 的老年代版本,都是單線程收集器,只啟用一條 GC 線程,都適合客戶端應(yīng)用。它們唯一的區(qū)別就是:Serial Old 工作在老年代,使用“標(biāo)記-整理”算法;Serial 工作在新生代,使用“復(fù)制”算法。
Parallel Old 收集器是 Parallel Scavenge 的老年代版本,追求 CPU 吞吐量。
CMS(Concurrent Mark Sweep,并發(fā)標(biāo)記清除)收集器是以獲取最短回收停頓時(shí)間為目標(biāo)的收集器(追求低停頓),它在垃圾收集時(shí)使得用戶線程和 GC 線程并發(fā)執(zhí)行,因此在垃圾收集過(guò)程中用戶也不會(huì)感到明顯的卡頓。
初始標(biāo)記:Stop The World,僅使用一條初始標(biāo)記線程對(duì)所有與 GC Roots 直接關(guān)聯(lián)的對(duì)象進(jìn)行標(biāo)記。
并發(fā)標(biāo)記:使用多條標(biāo)記線程,與用戶線程并發(fā)執(zhí)行。此過(guò)程進(jìn)行可達(dá)性分析,標(biāo)記出所有廢棄對(duì)象。速度很慢。
重新標(biāo)記:Stop The World,使用多條標(biāo)記線程并發(fā)執(zhí)行,將剛才并發(fā)標(biāo)記過(guò)程中新出現(xiàn)的廢棄對(duì)象標(biāo)記出來(lái)。
并發(fā)清除:只使用一條 GC 線程,與用戶線程并發(fā)執(zhí)行,清除剛才標(biāo)記的對(duì)象。這個(gè)過(guò)程非常耗時(shí)。
并發(fā)標(biāo)記與并發(fā)清除過(guò)程耗時(shí)最長(zhǎng),且可以與用戶線程一起工作,因此,總體上說(shuō),CMS 收集器的內(nèi)存回收過(guò)程是與用戶線程一起并發(fā)執(zhí)行的。
CMS 的缺點(diǎn):
吞吐量低
無(wú)法處理浮動(dòng)垃圾
使用“標(biāo)記-清除”算法產(chǎn)生碎片空間,導(dǎo)致頻繁 Full GC
對(duì)于產(chǎn)生碎片空間的問(wèn)題,可以通過(guò)開(kāi)啟 -XX:+UseCMSCompactAtFullCollection,在每次 Full GC 完成后都會(huì)進(jìn)行一次內(nèi)存壓縮整理,將零散在各處的對(duì)象整理到一塊。設(shè)置參數(shù) -XX:CMSFullGCsBeforeCompaction 告訴 CMS,經(jīng)過(guò)了 N 次 Full GC 之后再進(jìn)行一次內(nèi)存整理。
G1 是一款面向服務(wù)端應(yīng)用的垃圾收集器,它沒(méi)有新生代和老年代的概念,而是將堆劃分為一塊塊獨(dú)立的 Region。當(dāng)要進(jìn)行垃圾收集時(shí),首先估計(jì)每個(gè) Region 中垃圾的數(shù)量,每次都從垃圾回收價(jià)值最大的 Region 開(kāi)始回收,因此可以獲得最大的回收效率。
從整體上看, G1 是基于“標(biāo)記-整理”算法實(shí)現(xiàn)的收集器,從局部(兩個(gè) Region 之間)上看是基于“復(fù)制”算法實(shí)現(xiàn)的,這意味著運(yùn)行期間不會(huì)產(chǎn)生內(nèi)存空間碎片。
這里拋個(gè)問(wèn)題
一個(gè)對(duì)象和它內(nèi)部所引用的對(duì)象可能不在同一個(gè) Region 中,那么當(dāng)垃圾回收時(shí),是否需要掃描整個(gè)堆內(nèi)存才能完整地進(jìn)行一次可達(dá)性分析?
并不!每個(gè) Region 都有一個(gè) Remembered Set,用于記錄本區(qū)域中所有對(duì)象引用的對(duì)象所在的區(qū)域,進(jìn)行可達(dá)性分析時(shí),只要在 GC Roots 中再加上 Remembered Set 即可防止對(duì)整個(gè)堆內(nèi)存進(jìn)行遍歷。
如果不計(jì)算維護(hù) Remembered Set 的操作,G1 收集器的工作過(guò)程分為以下幾個(gè)步驟:
初始標(biāo)記:Stop The World,僅使用一條初始標(biāo)記線程對(duì)所有與 GC Roots 直接關(guān)聯(lián)的對(duì)象進(jìn)行標(biāo)記。
并發(fā)標(biāo)記:使用一條標(biāo)記線程與用戶線程并發(fā)執(zhí)行。此過(guò)程進(jìn)行可達(dá)性分析,速度很慢。
最終標(biāo)記:Stop The World,使用多條標(biāo)記線程并發(fā)執(zhí)行。
篩選回收:回收廢棄對(duì)象,此時(shí)也要 Stop The World,并使用多條篩選回收線程并發(fā)執(zhí)行。
本文由mdnice多平臺(tái)發(fā)布
本文使用 文章同步助手 同步
標(biāo)簽: