最近恰好有時間,就簡單的看了下JVM的幾種垃圾回收器,它們都是計算機歷史發展的產物,先簡單的作一個整理,並無哪一款垃圾收集器就必定是最優,還須要結合使用場景、參數配置等進行考量,根據系統狀況搭配出儘量合理優質的垃圾回收策略,而這每每須要經驗的積累;html
若是說收集算法是內存回收的方法論,垃圾收集器就是內存回收的具體實現。java
下圖展現了7種做用於不一樣分代的收集器,若是兩個收集器之間存在連線,就說明它們能夠搭配使用。算法
併發與並行編程
這兩個名詞都是併發編程中的概念,在談論垃圾收集器的上下文語境中,它們能夠解釋以下。服務器
並行(Parallel):指多條垃圾收集線程並行工做,但此時用戶線程仍然處於等待狀態。多線程
併發(Concurrent):指用戶線程與垃圾收集線程同時執行(但不必定是並行的,可能會交替執行),用戶程序在繼續運行,而垃圾收集程序運行於另外一個CPU上。併發
Serial收集器 [ˈsɪəriəl]性能
Serial 收集器是最基本、歷史最悠久的收集器,曾經(在JDK 1.3.1以前)是虛擬機年輕代收集的惟一選擇。優化
特性網站
年輕代,單線程收集器,但它的「單線程」的意義並不只僅說明它只會使用一個CPU或一條收集線程去完成垃圾收集工做,更重要的是在它進行垃圾收集時,必須暫停其餘全部的工做線程(Stop the world),直到它收集結束。
優點
簡單而高效(與其餘收集器的單線程比),對於限定單個CPU的環境來講,Serial收集器因爲沒有線程交互的開銷,專心作垃圾收集天然能夠得到最高的單線程收集效率。
應用場景
在用戶的桌面應用場景中,分配給虛擬機管理的內存通常來講不會很大,收集兒十兆甚至一兩百兆的新生代(僅僅是新生代使用的內存,桌面應用基本上不會再大了),停頓時間徹底能夠控制在幾十毫秒最多一百多毫秒之內,只要不是頻繁發生,這點停頓是能夠接受的。因此,Serial 收集器對於運行在Client模式下的虛擬機來講是一個很好的選擇。
參數控制
-XX:+UseSerialGC -- 串行收集器
ParNew收集器
ParNew收集器其實就是Serial收集器的多線程版本;
特性
ParNew收集器其實就是Serial收集器的多線程版本,除了使用多條線程進行垃圾收集以外,其他行爲包括Serial收集器可用的全部控制參數、收集算法、Stop The World、對象分配規則、回收策略等都與Serial收集器徹底同樣,在實現上,這兩種收集器也共用了至關多的代碼。
優點
隨着可使用的CPU的數量的增長,它對於GC時系統資源的有效利用仍是頗有好處的。
它默認開啓的收集線程數與CPU的數量相同,在CPU很是多(譬如32個,如今CPU動輒就4核加超線程,服務器超過32個邏輯CPU的狀況愈來愈多了)的環境下,可使用-XX: ParaIlelGCThreads參數來限制垃圾收集的線程數。
劣勢
ParNew收集器在單CPU的環境中絕對不會有比Serial收集器更好的效果,甚至因爲存在線程交互的開銷,該收集器在經過超線程技術實現的兩個CPU的環境中都不能百分之百地保證能夠超越Serial收集器。
應用場景
ParNew收集器是許多運行在Server模式下的虛擬機中首選的新生代收集器。
參數控制
-XX:+UseParNewGC -- ParNew 年輕代收集器
-XX:ParaIlelGCThreads -- 限制垃圾收集的線程數
備註
除了Serial收集器外,目前只有它能與CMS收集器配合工做。
Parallel Scavenge收集器 [ˈpærəlel] [ˈskævɪndʒ]
特性
相比其餘收集器,Parallel收集器更關注系統的吞吐量。
吞吐量 = 運行用戶代碼時間 / (運行用戶代碼時間 + 垃圾收集時間)
優點
GC自適應的調節策略,當使用-XX:+UseAdaptiveSizePolicy參數後,就不須要手工指定新生代的大小、Eden與Survivor區的比例、晉升老年代對象年齡等細節參數了,只須要把基本的內存數據設置好(如-Xmx),而後使用MaxGCPauseMillis參數或GCTimeRatio參數給VM設立一個優化目標,虛擬機會根據當前系統的運行狀況收集性能監控信息,動態調整這些參數以提供最合適的停頓時間或者最大的吞吐量,這種調節方式稱爲GC自適應的調節策略(GC Ergonomics)。
應用場景
若是對於收集器運做原理不太瞭解,手工優化存在困難的時候,使用Parallel Scavenge收集器配合自適應調節策略,把內存管理的調優任務交給虛擬機去完成將是一個很不錯的選擇。
參數控制
-XX:+UseParallelGC -- 使用Parallel收集器 + 老年代串行
-XX:+UseAdaptiveSizePolicy -- GC自適應的調節策略
收集器提供了兩個參數用於精確控制吞吐量:
-XX:MaxGCPauseMillis -- 最大垃圾收集停頓時間,是一個大於0的毫秒數,收集器將盡力保證內存回收花費的時間不超過設定值,可是GC停頓時間縮短是以犧牲吞吐量和新生代空間來換取的;
-XX:GCTimeRatio -- 直接設置吞吐量大小();默認值爲99,就是容許最大1%的垃圾收集時間。
Serial Old收集器
Serial Old是Serial收集器的老年代版本。
特性
老年代,單線程收集器,使用「標記-整理」算法。
優點
應用場景
①Client模式
Serial Old收集器的主要意義也是在於給Client模式下的虛擬機使用。
②Server模式
若是在Server模式下,那麼它主要還有兩大用途:一種用途是在JDK 1.5以及以前的版本中與Parallel Scavenge收集器搭配使用,另外一種用途就是做爲CMS收集器的後備預案,在併發收集發生Concurrent Mode Failure時使用。
參數控制
備註
Parallel Old收集器
Parallel Old是Parallel Scavenge收集器的老年代版本。
特性
老年代,多線程收集器,使用「標記—整理」算法,該收集器在JDK1.6中才開始提供。
優點
應用場景
在注重吞吐量以及CPU資源敏感的場合,均可以優先考慮Parallel Scavenge + Parallel Old收集器二者的組合。
參數控制
-XX:+UseParallelOldGC -- 使用Parallel收集器+ 老年代並行
CMS收集器
CMS(Concurrent Mark Sweep)收集器,是一種以獲取最短回收停頓時間爲目標的收集器。
特性
從名字(包含「Mark Sweep」)上就能夠看出CMS收集器是基於「標記-清除」算法實現的,它的運做過程相對於前面幾種收集器來講要更復雜一些,整個過程分爲4個步驟,包括:
①初始標記(CMS initial mark):僅僅只是標記一下GC Roots能直接關聯到的對象,速度很快,須要「Stop The World」。
②併發標記(CMS concurrent mark):經過根搜索算法(GC Roots Tracing)判斷對象是否仍在使用中。
③從新標記(CMS remark):爲了修正併發標記期間因用戶程序繼續運做而致使標記產生變更的那一部分對象的標記記錄,這個階段的停頓時間通常會比初始標記階段稍長一些,但遠比並發標記的時間短,仍然須要「Stop The World」。
④併發清除(CMS concurrent sweep):清除標記對象。
優點
併發收集,低停頓。
缺點
①CMS收集器對CPU資源很是敏感:其實,面向併發設計的程序都對CPU資源比較敏感。在併發階段,它雖然不會致使用戶線程停頓,可是會由於佔用了一部分線程(或者說CPU資源)而致使應用程序變慢,總吞吐量會下降。
②CMS收集器沒法處理浮動垃圾:因爲CMS併發清理階段用戶線程還在運行着,伴隨程序運行天然就還會有新的垃圾不斷產生,這一部分垃圾出如今標記過程以後,CMS沒法在當次收集中處理掉它們,只好留待下一次GC時再清理掉,這一部分垃圾就稱爲「浮動垃圾」。
③CMS收集器會產生大量空間碎片:CMS是一款基於「標記—清除」算法實現的收集器,這意味着收集結束時會有大量空間碎片產生。空間碎片過多時,將會給大對象分配帶來很大麻煩,每每會出現老年代還有很大空間剩餘,可是沒法找到足夠大的連續空間來分配當前對象,不得不提早觸發一次Full GC。爲了解決這個問題,CMS收集器提供了兩個開關參數-XX:+ UseCMSCompactAtFullCollection && -XX:+CMSFullGCsBeforeCompaction;
應用場景
目前很大一部分的Java應用集中在互聯網站或者B/S系統的服務端上,這類應用尤爲重視服務的響應速度,但願系統停頓時間最短,以給用戶帶來較好的體驗。CMS收集器就很是符合這類應用的需求。
參數控制
-XX:+UseConcMarkSweepGC -- 使用CMS收集器
-XX:+ UseCMSCompactAtFullCollection -- 用於在「享受」完FullGC以後,免費附贈一次碎片整理過程,因爲內存整理的過程是沒法併發的,因此時間會比較長;
-XX:+CMSFullGCsBeforeCompaction -- 用於執行完N次不壓縮FullGC以後,跟着來一次帶壓縮的;
-XX:ParallelCMSThreads(後期又稱爲ConcGCThreads) -- 定義併發CMS過程運行時的線程數。若是該標誌未設置,JVM會根據並行收集器中的-XX:ParallelGCThreads參數的值來計算出默認的並行CMS線程數。ParallelCMSThreads = (ParallelGCThreads + 3)/4,ParallelGCThreads默認會被設置爲CPU的數量;
G1收集器
G1收集器是垃圾收集器理論進一步發展的產物,HotSpot開發團隊賦予它的使命是將來能夠替換掉JDK 1.5中發佈的CMS收集器。
G1收集器打破了年輕代與老年代的物理界限。
取而代之的是,G1算法將堆劃分爲若干個區域(Region),它仍然屬於分代收集器。以下圖所示,堆被分爲 Eden、Survivor、old generation區。此外,還有第四種類型的對象被稱爲巨無霸區域(Humongous regions),用來保存比標準塊(standard region)大50%及以上的對象,它們存儲在一組連續的區中,最後一個類型是堆內存中的未使用區(unused areas).
特性
基於「標記一整理」算法,可獨立完成分代收集,打破年輕代與老年代的物理界限,可預測停頓;
優點
①不會產生內存碎片:基於「標記一整理」算法,也就是說它不會產生空間碎片,這對於長時間運行的應用系統來講很是重要。同時也不會由於分配大對象時沒法找到連續內存空間而提早觸發下一次GC。
②可預測停頓:它能夠很是精確地控制停頓,既能讓使用者明確指定在一個長度爲M毫秒的時間片斷內,消耗在垃圾收集上花費的時間不得超過N毫秒,這幾乎已是實時Java (RTSJ)的垃圾收集器的特徵。
應用場景
能夠像CMS收集器同樣,GC操做與應用的線程一塊兒併發執行;
須要可預測的GC暫停耗時;
參數控制
-XX:+UseG1GC -- 啓用G1收集器
-XX:MaxGCPauseMillis -- 設置GC的最大暫停時間(單位:毫秒)
-XX:InitiatingHeapOccupancyPercent -- 啓動併發GC時的堆內存佔比,基於整個堆的使用率,而不僅是某一代內存的使用比例;默認值爲 45;值爲 0 則表示「一直執行GC循環「;
備註
①不要設置年輕代的大小(Young Generation Size),倘若經過 -Xmn 顯式地指定了年輕代的大小, 則會干擾到 G1收集器的默認行爲;
②設置 MaxGCPauseMillis 時不該該使用平均響應時間做爲指標,而應該考慮使用目標時間的90%或者更大做爲響應時間指標.。也就是說90%的用戶請求響應時間不會超過預設的目標值,不過該暫停時間只是一個目標,並不能保證老是獲得知足。
參考:
《深刻理解Java虛擬機:JVM高級特性與最佳實踐_周志明》
java垃圾回收器:http://www.jianshu.com/p/50d5c88b272d
http://www.cnblogs.com/ityouknow/p/5614961.html