主要介紹HotSpot虛擬機的垃圾收集器,這個虛擬機包含的全部收集器如圖所示:算法
能夠看到,收集器之間是能夠搭配使用的。下面介紹這些收集器的特性、基本原理和使用場景。在介紹以前先明確一個觀點:直到如今爲止尚未最好的收集器出現,更加沒有萬能的收集器,選擇的是對具體應用最合適的收集器。多線程
串行收集器是最基本、發展歷史最悠久的收集器。它們的特色就是單線程運行及獨佔式運行,所以會帶來很很差的用戶體驗。雖然它的收集方式對程序的運行並不友好,但因爲它的單線程執行特性,應用於單個CPU硬件平臺的性能能夠超過其餘的並行或併發處理器。併發
經過JVM參數-XX:+UseSerialGC可使用串行垃圾回收器。性能
Serial與Serial Old工做過程如圖: 線程
要啓用老年代串行收集器,能夠嘗試使用下面的參數:3d
並行收集器是多線程的收集器,在多核CPU下可以很好的提升收集性能。cdn
ParNew收集器是Serial收集器的多線程版本。除了使用多條線程進行垃圾收集以外,其他行爲如全部控制參數(例如:-XX:SurvivorRatio、-XX:PretenureSizeThreshold、-XX:HandlePromotionFailure等)、收集算法、Stop The World、對象分配規則、回收策略等都與Serial收集器徹底同樣,在實現上,這兩種收集器也共用了至關多的代碼。ParNew收集器的工做過程以下圖所示:對象
開啓ParNew收集器可使用如下參數:blog
ParNew是並行的收集器,在這裏介紹一下並行與併發的概念內存
Parallel Scavenge收集器與ParNew收集器相似,也是使用複製算法的並行的多線程新生代收集器。但Parallel Scavenge收集器關注可控制的吞吐量(Throughput)
注:吞吐量是指CPU用於運行用戶代碼的時間與CPU總消耗時間的比值,即吞吐量 = 運行用戶代碼時間 /( 運行用戶代碼時間 + 垃圾收集時間 )
Parallel Scavenge收集器提供了兩個參數用於精確控制吞吐量:
除上述兩個參數以外,Parallel Scavenge收集器還提供了一個參數-XX:+UseAdaptiveSizePolicy,當這個參數打開以後,就不須要手工指定新生代的大小(-Xmn)、Eden與Survivor區的比例(-XX:SurvivorRatio)、晉升老年代對象年齡(-XX:PretenureSizeThreshold)等細節參數了,虛擬機會根據當前系統的運行狀況收集性能監控信息,動態調整這些參數以提供最合適的停頓時間或者最大的吞吐量,這種調節方式稱爲GC自適應的調節策略(GC Ergonomics)。自適應調節策略也是Parallel Scavenge收集器與ParNew收集器的一個重要區別。
Parallel Old是Parallel Scavenge收集器的老年代版本,使用多線程和「標記-整理」算法。這個收集器是在JDK 1.6中才開始提供的。
因爲若是新生代選擇了Parallel Scavenge收集器,老年代除了Serial Old(PS MarkSweep)收集器外別無選擇(Parallel Scavenge沒法與CMS收集器配合工做),Parallel Old收集器的出現就是爲了解決這個問題。Parallel Scavenge和Parallel Old收集器的組合更適用於注重吞吐量以及CPU資源敏感的場合。Parallel Old收集器的工做過程下圖所示:
CMS(Concurrent Mark Sweep)收集器是一種以獲取最短回收停頓時間爲目標的收集器,也是基於「標記—清除」算法實現的,它的運做整個過程過程細分爲4個步驟,包括:
因爲整個過程當中耗時最長的併發標記和併發清除過程當中,收集器線程均可以與用戶線程一塊兒工做,因此整體上來講,CMS收集器的內存回收過程是與用戶線程一塊兒併發地執行,如圖:
CMS有如下3個明顯的缺點:
CMS收集器對CPU資源很是敏感。CMS默認啓動的回收線程數是( CPU Count + 3 ) / 4,當CPU在4個以上時,併發回收時垃圾收集線程很多於25%的CPU資源,而且隨着CPU數量的增長而降低。可是當CPU不足4個(譬如2個)時,將分出一半的運算能力去執行收集器線程,就可能致使用戶程序的執行速度突然下降了50%。
CMS收集器沒法處理浮動垃圾(Floating Garbage),可能出現「Concurrent Mode Failure」失敗而致使另外一次Full GC的產生。浮動垃圾是指CMS在併發清理階段用戶線程還在同時執行時產生的垃圾。因爲在垃圾收集階段用戶線程還須要運行,還須要預留有足夠的內存空間給用戶線程使用,所以須要預留一部分空間提供併發收集時的程序運做使用。在JDK 1.5的默認設置下,CMS收集器當老年代使用了68%的空間後就會被激活,能夠適當調高參數-XX:CMSInitiatingOccupancyFraction的值來提升觸發百分比,以下降內存回收次數;在JDK 1.6中,CMS收集器的啓動閾值已經提高至92%。若是運行期間預留的內存沒法知足程序須要,就會出現一次「Concurrent Mode Failure」失敗,這時虛擬機將臨時啓用Serial Old收集器來從新進行老年代的垃圾收集,致使停頓時間就很長了。因此說參數-XX:CMSInitiatingOccupancyFraction設置得過高很容易致使大量「Concurrent Mode Failure」失敗,性能反而下降。
CMS是一款基於「標記—清除」算法實現的收集器,收集結束時會有大量空間碎片產生。空間碎片過多沒法找到足夠大的連續空間來分配當前對象,不得不提早觸發一次Full GC。爲了解決這個問題,CMS收集器提供了一個-XX:+UseCMSCompactAtFullCollection開關參數(默認就是開啓的),用於在CMS收集器要進行Full GC時開啓內存碎片的合併整理過程,內存整理的過程是沒法併發的,所以也會致使停頓時間變長。而另一個參數-XX:CMSFullGCsBeforeCompaction能夠設置執行多少次不壓縮的Full GC後,才執行一次帶壓縮的(默認值爲0,即每次進入Full GC時都進行碎片整理)。
G1是一款面向服務端應用的垃圾收集器,與其餘GC收集器相比,G1具有以下特色:
G1根據各個Region回收所得到的空間大小以及回收所需時間等指標在後臺維護一個優先列表,每次根據容許的收集時間,優先回收價值最大的Region,從而能夠有計劃地避免在整個Java堆中進行全區域的垃圾收集。
G1收集器運做步驟以下:
參數 | 描述 |
---|---|
UseSerialGC | 虛擬機運行在Client模式下的默認值,打開此開關後,使用 Serial+Serial Old 的收集器組合進行內存回收 |
UseParNewGC | 打開此開關後,使用 ParNew + Serial Old 的收集器組合進行內存回收 |
UseConcMarkSweepGC | 打開此開關後,使用 ParNew + CMS + Serial Old 的收集器組合進行內存回收。Serial Old 收集器將做爲 CMS 收集器出現 Concurrent Mode Failure 失敗後的後備收集器使用 |
UseParallelGC | 虛擬機運行在 Server 模式下的默認值,打開此開關後,使用 Parallel Scavenge + Serial Old(PS MarkSweep) 的收集器組合進行內存回收 |
UseParallelOldGC | 打開此開關後,使用 Parallel Scavenge + Parallel Old 的收集器組合進行內存回收 |
SurvivorRatio | 新生代中 Eden 區域與 Survivor 區域的容量比值,默認爲8,表明 Eden : Survivor = 8 : 1 |
PretenureSizeThreshold | 直接晉升到老年代的對象大小,設置這個參數後,大於這個參數的對象將直接在老年代分配 |
MaxTenuringThreshold | 晉升到老年代的對象年齡,每一個對象在堅持過一次 Minor GC 以後,年齡就增長1,當超過這個參數值時就進入老年代 |
UseAdaptiveSizePolicy | 動態調整 Java 堆中各個區域的大小以及進入老年代的年齡 |
HandlePromotionFailure | 是否容許分配擔保失敗,即老年代的剩餘空間不足以應付新生代的整個 Eden 和 Survivor 區的全部對象都存活的極端狀況 |
ParallelGCThreads | 設置並行GC時進行內存回收的線程數 |
GCTimeRatio | GC 時間佔總時間的比率,默認值爲99,即容許 1% 的GC時間,僅在使用 Parallel Scavenge 收集器生效 |
MaxGCPauseMillis | 設置 GC 的最大停頓時間,僅在使用 Parallel Scavenge 收集器時生效 |
CMSInitiatingOccupancyFraction | 設置 CMS 收集器在老年代空間被使用多少後觸發垃圾收集,默認值爲 68%,僅在使用 CMS 收集器時生效 |
UseCMSCompactAtFullCollection | 設置 CMS 收集器在完成垃圾收集後是否要進行一次內存碎片整理,僅在使用 CMS 收集器時生效 |
CMSFullGCsBeforeCompaction | 設置 CMS 收集器在進行若干次垃圾收集後再啓動一次內存碎片整理,僅在使用 CMS 收集器時生效 |