我的博客項目地址git
但願各位幫忙點個star,給我加個小星星✨github
上一篇介紹的垃圾回收算法是內存回收的方法論,垃圾收集器就是垃圾回收的具體實現。算法
不一樣廠商、不一樣版本的虛擬機所提供的垃圾收集器可能會有很大差異,書中主要講的是HotSpot虛擬機的垃圾收集器(在JDK1.7中正式提供了商用的G1收集器)。服務器
(圖片來源網絡,侵權刪)網絡
圖中展現了7種做用於不一樣年代的收集器,若是兩個收集器之間存在連線,就說明它們能夠搭配使用。虛擬機所處的區域,則表示它是屬於新生代仍是老年代收集器。多線程
Serial 收集器是最基本、發展歷史最悠久的收集器,曾經(在JDK1.3.1以前)是虛擬機新生代收集的惟一選擇。併發
簡單介紹: ParNew收集器其實就是Serial收集器的多線程版本,除了使用多條線程進行垃圾收集以外,其他行爲包括Serial收集器可用的全部控制參數、收集算法、Stop The World、對象分配規則、回收策略等都與Serial收集器徹底同樣。佈局
應用場景: 在Server模式下的虛擬機中首選的新生代收集器,其中一個緣由,是除了Serial收集器外,目前只有它能與CMS收集器配合工做。 不幸的是,CMS做爲老年代的收集器,卻沒法與JDK1.4.0中已經存在的新生代收集器Parallel Scavenge配合工做,因此在JDK1.5使用CMS來收集老年代的時候,新生代只能選擇ParNew或者Serial收集器中的一個。ParNew收集器也是使用**-XX:+UseConcMarkSweepGC選項後的默認新生代收集器,也可使用-XX:+UseParNewGC**選項來強制制定它。性能
ParNew和Serial比較: ParNew收集器在單CPU的環境中絕對不會比Serial收集器更好的效果,甚至因爲存在線程交互的開銷,該收集器在經過超線程技術實現的兩個CPU的環境都不能百分之百地保證能夠超越Serial收集器。 固然,隨着可使用的CPU的數量的增長,它對GC時系統資源的有效利用仍是頗有好處的。它默認開啓的收集線程數與CPU的數量相同,在CPU很是多的狀況下,可使用**-XX:ParallelGCThreads參數來限制垃圾收集的線程數**。學習
簡單介紹: Parallel Scavenge收集器是一個新生代收集器,它也是使用複製算法的收集器,是並行的多線程收集器。
應用場景: 停頓時間越短就越適合須要與用戶交互的程序,高吞吐量能夠高效率地利用CPU時間,儘快完成程序的運算任務,主要適合在後臺運算而不須要太多交互的任務。
對比分析:
簡單介紹: Serial Old是Serial收集器的老年代版本,它一樣是一個單線程收集器,使用**「標記-整理」算法**。
應用場景: 這個收集器的主要意義也是在於給Client模式下的虛擬機使用。 若是在Server模式下,它還有兩大用途:
簡單介紹: Parallel Old是Parallel Scavenge收集器的老年代版本,使用多線程和**「標記-整理」法**。 這個收集器是在JDK1.6中才開始提供的,在此以前,新生代的Parallel Scavenge收集器一直處於比較尷尬的狀態,由於若是新生代選擇了Parallel Scavenge收集器,老年代除了Serial Old(PS MarkSweep)收集器以外別無選擇。 因爲老年代Serial Old收集器在服務端應用性能上的「拖累」,使用了Parallel Scavenge收集器未必能在總體應用上得到吞吐量最大化的效果,因爲單線程的老年代收集中沒法充分利用服務器多CPU的處理能力,在老年代很大並且硬件比較高級的環境中,這種組合的吞吐量甚至還不必定有ParNew加CMS的組合好。
應用場景: 直到Parallel Old收集器出現後,「吞吐量優先」收集器終於有了比較名副其實的應用組合,在注重吞吐量以及CPU資源敏感的場合,均可以優先考慮Parallel Scavenge加Parallel Old收集器。
簡單介紹: CMS(Concurrent Mark Sweep)收集器是一種以獲取最短回收停頓時間爲目標的收集器。 CMS收集器是基於**「標記-清除」**算法實現的,整個過程分爲四個步驟:
初始標記(CMS initial mark) 僅僅只是標記一下GC Roots能直接關聯到的對象,速度很快。
併發標記(CMS concurrent mark) 進行GC Roots Tracing的過程
從新標記(CMS remark) 爲了修正併發標記期間因用戶程序繼續運做而致使標記產生變更的那一部分對象的標記記錄,這個階段的停頓時間通常會比初始標記階段稍長些,但遠比並發標記的時間短。
併發清除(CMS concurrent sweep)
其中,初始標記、從新標記這兩個步驟仍然須要**「Stop The World」。因爲整個過程當中耗時最長的併發標記和併發清除過程**收集器線程均可以與用戶線程一塊兒工做,因此,從整體上來講,CMS收集器的內存回收過程是與用戶線程一塊兒併發執行的。
優勢: 併發收集、低停頓
缺點:
CMS收集器對CPU資源很是敏感 在併發階段,它雖然不會致使用戶線程卡頓,可是會由於佔用了一部分線程(或者說CPU資源)而致使應用程序變慢,總吞吐量會下降。 CMS默認啓動的回收線程是(CPU數量+3)/ 4,也就是當CPU在4個以上是,併發回收時垃圾收集線程很多於25%的CPU資源,而且隨着CPU數量的增長而降低。可是當CPU不足4個時,CMS對用戶程序的影響就可能變得更大。
CMS收集器沒法處理浮動垃圾(Floating Garbage) 可能出現「Concurrent Mode Failure」失敗而致使另外一次Full GC的產生。 因爲CMS併發清理階段用戶線程還在運行着,伴隨程序運行天然就還會有新的垃圾不斷產生,這一部分垃圾出現標記過程以後,CMS沒法在當次收集中處理掉它們,只好留待下一次GC時再清理掉。這一部分垃圾就成爲「浮動垃圾」。 因爲在垃圾收集階段用戶線程還須要運行,那也就還須要預留有足夠的內存空間給用戶線程使用,所以CMS收集器不能像其它收集器那樣等到老年代幾乎完成被填滿再進行收集,須要預留一部分空間提供併發收集時的程序運做使用。
收集結束時會有大量空間碎片產生 「標記-清理」算法,意味着收集結束時會有大量空間碎片產生。空間碎片過多時,將會給大對象分配帶來很大麻煩,每每會出現老年代還有很大空間剩餘,可是沒法找到足夠大的連續空間來分配當前對象,不得不提早觸發一次Full GC。
簡單介紹: **G1(Garbage-First)**收集器是當前收集器技術發展的最前沿成果之一。它是一款面向服務端應用的垃圾收集器,具有如下特色:
並行與併發 G1能充分利用多CPU、多核環境下的硬件有時,使用多個CPU來縮短Stop-The-World停頓的時間,部分其它收集器本來須要停頓Java線程執行的GC動做,G1收集器仍然能夠經過併發的方式讓Java程序繼續運行。
分代收集 雖然G1能夠不須要其它收集器配合就能獨立管理整個GC堆,但它可以採用不一樣的方式去處理新建立的對象和已經存活了一段時間、熬過屢次GC的舊對象以獲取更好的收集結果。
空間整合 與CMS的「標記-清理」算法不一樣,G1從總體來看是基於「標記-整理」算法實現的收集器,從局部(兩個Region之間)上來看是基於「複製」算法實現的,但不管如何,這兩種算法都意味着G1運做期間不會產生內存空間碎片,收集後能提供規整的可用內存。這種特性有利於程序長時間運行,分配大對象時不會由於沒法找到連續內存空間而提早觸發下一次GC。
可預測的停頓 這是G1相對於CMS的另外一大優點,下降停頓時間是G1和CMS共同的關注點,但G1除了追求低停頓以外,還能創建可預測的停頓時間模型,能讓使用者明確指定在一個長度爲M毫秒的時間片斷內,消耗在垃圾收集上的時間不得超過N毫秒,這幾乎已是實時Java(RTSJ)的垃圾收集器的特徵了。
在G1以前的其餘收集器進行收集的範圍都是整個新生代或者老年代,而G1再也不是這樣。使用G1收集器時,Java堆的內存佈局就與其它收集器有很大差異,它將整個Java堆分爲多個大小相等的獨立區域(Region),雖然還保留有新生代和老年代的概念,但新生代和老年代再也不是物理隔離的了,它們都是一部分Region(不須要連續)的集合。
G1收集器之因此能創建可預測的停頓時間模型,是由於它能夠有計劃地避免在整個Java堆中進行全區域的垃圾收集。G1跟蹤各個Region裏面的垃圾堆積的價值大小(回收所得到的空間大小以及回收所需時間的經驗值),在後臺維護一個優先列表,每次根據容許的收集時間,優先回收價值最大的Region(這也是Garbage-First名稱的來由)。這種使用Region劃份內存空間以及有優先級的區域回收方式,保證了G1收集器在有限的時間內能夠獲取儘量高的收集效率。
初始標記(Initial Marking) 初始標記階段僅僅只是標記一下GC Roots能直接關聯到的對象,而且修改TAMS(Next Top at Mark Start)的值,讓下一階段用戶程序併發運行時,能在正確可用的Region中建立新對象,這個階段須要停頓線程,但耗時很短。
併發標記(Concurrent Marking) 併發標記階段是從GC Root開始對堆中對象進行可達性分析,找出存活的對象,這階段耗時較長,但可與用戶程序併發執行。
最終標記(Final Marking) 最終標記階段則是爲了修正在併發標記期間因用戶程序繼續運做而致使標記產生變更的那一部分標記記錄,虛擬機將這段時間對象變化記錄在Remembered Set Logs裏面,該階段會把Remembered Set Logs的數據合併到Remembered Set中,這階段須要停頓線程,可是可並行執行。
篩選回收(Live Data Counting and Evacuation) 篩選回收階段首先對各個Region的回收價值和成本進行排序,根據用戶所期待的GC停頓時間來制定回收計劃這個階段其實能夠作到與用戶程序一塊兒併發執行,可是由於只回收一部分Region,時間是用戶可控制的,並且停頓用戶線程將大幅提升收集效率。
上面記錄了這麼多垃圾收集器的特色和優缺點,並無說哪一個最好的,以爲具體使用仍是看業務要求吧。
瞭解完GC算法和垃圾收集器後,下一篇好好學習一下JVM經常使用命令吧。