Serial收集器
它的缺點是當它想要進行垃圾回收時,必須暫停用戶的全部進程,即stop the world。到如今爲止它依然是虛擬機運行在client模式下的默認年輕代收集器,與其餘收集器相比,對於限定在單個cpu的運行環境來講,Serial收集器因爲沒有線程交互的開銷,專心作垃圾回收天然能夠得到高效的單線程收集效率。
Serial Old是它的年老代版本。它一樣是一個單線程收集器,使用標記-總體的算法。這個收集器的主要意義也是被client模式下的虛擬機使用。在Server模式下,他有主要的兩大用途,一個是在JDK1.5以及之前的版本中與Parallel Scanvenge收集器搭配使用,另外一個就是做爲CMS收集器的後備預案,在併發收集發生Concurrent ModeFailure的時候使用。
經過指定-UseSerialGC參數,使用Serial+Serial Old的串行收集器組合進行垃圾回收。
ParNew收集器
它是Serial收集器年輕代的多線程實現,注意在進行垃圾回收時依舊是stop the world,只是相對serial時它會運行多條進程進行垃圾回收。
ParNew收集器在單CPU的環境中絕對不會有比Serial收集器更好的效果,甚至因爲存在線程交互的開銷,該收集器在經過超線程技術實現的兩個CPU的環境中都不能百分之百的保證能超越Serial收集器。固然,隨着可使用的CPU的數量增長,它對於GC時系統資源的利用仍是頗有好處的。它默認開啓的收集線程數與CPU的數量相同,在CPU很是多(譬如32個,如今CPU動輒4核加超線程,服務器超過32個邏輯CPU的狀況愈來愈多了)的環境下,可使用-XX:ParallelGCThreads參數來限制垃圾收集的線程數。
-UserParNewGC,打開此開關後,使用ParNew+Serial Old的收集器組合進行內存回收,這樣年輕代使用並行收集器,年老代使用串行收集器。
Parallel Scanvenge收集器
Parallel是採用複製算法的多線程年輕代垃圾回收器,彷佛與ParNew收集器有不少相同的地方。可是這個收集器所關注的目標是吞吐量。所謂吞吐量就是CPU用於運行用戶代碼的時間和CPU總消耗時間的比值,也就是(吞吐量=運行用戶代碼的時間/(運行用戶代碼的時間+垃圾回收的時間))停頓時間越短就越適合須要與用戶交互的程序。良好的響應速度可以提高用戶的體驗;而高吞吐量則能夠最高效率的利用cpu時間,儘快的完成程序的運算任務,主要適合後臺運算而不須要太多交互的任務。
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收集器。
-UseParallelGC: 虛擬機運行在Server模式下的默認值,打開此開關後,使用Parallel Scavenge + Serial Old的收集器組合進行內存回收。-UseParallelOldGC: 打開此開關後,使用Parallel Scavenge + Parallel Old的收集器組合進行垃圾回收
CMS(Concurrent mark swep)收集器
是一個比較重要的收集器,如今應用很是普遍。CMS是一種獲取最短回收停頓時間爲目標的收集器,這使得他很適合於和用戶交互的業務。從名字能夠看出它是基於標記清除算法的,四個步驟:
初始標記(initial mark);併發標記(concurrent mark);從新標記(remark);併發清除(concurrent sweep)。
初始標記和從新標記仍是會stop the world,可是在耗費時間更長的併發標記和併發清除兩個階段均可以和用戶進程同時工做。
不過因爲CMS收集器是基於標記清除算法實現的,會致使有大量的空間碎片產生,在爲大對象分配內存的時候,每每會出現年老代還有很大的空間剩餘,可是沒法找到足夠大的連續空間來分配當前對象,不得不提早開啓一次full gc爲了解決這個問題,CMS收集器默認提供了一個-xx:+UseCMSCompactAtFullCollection收集開關參數(默認就是開啓的),用於在CMS收集器進行Full gc完開啓內存碎片的合併整理過程,內存整理的過程是沒法併發的,這樣內存碎片問題卻是沒有了,可是停頓時間不得不變長,虛擬機還提供了另外一個參數:-xx:CMSFullGCSBeforeCopaction參數用於設置執行多少次不壓縮的Full gc後跟着來一次壓縮,默認爲0,也就是每次進入Full gc 都進行碎片整理。
不幸的是,它做爲年老代收集器,沒法與jdk1.4中已經存在的年輕代收集器Parallel Scavenge配合工做,因此在jdk1.5中使用cms收集年老代時,年輕代只能選擇ParNew或者Serial收集器的其中一個。ParNew是使用-xx:+UseConcMarkSweepGC選項啓用CMS收集器後的默認年輕代收集器,也可使用-xx:+UseParNewGC選項來強制指定它。
CMS算法的幾個經常使用參數
UseCMSInitatingOccupancyOnly:表示只在到達閾值的時候,才進行CMS回收,爲了減小第二次暫停時間,經過-xx:+CMSParallelRemarkEnabled開啓並行remark。若是remark時間仍是過長,能夠開啓-xx:+CMSScavengeBeforeRemark,強制remark以前開啓一次minor gc,減小remark的暫停時間,可是在remark以後也當即開啓一次minor gc。
CMS默認啓動的回收線程數目是(parallelGCThreads+3)/4,而且也能夠經過-xx:+ParallelCMSThreads來設定,其中-xx:ParallelGCThreads表明的年輕代的併發收集線程數目。
CMSClassUnloadingEnabled:容許對類元數據進行回收。
CMSInitatingPermOccupancyFraction:當永久區佔用率達到這一百分比後,啓動 CMS 回收 (前提是-XX:+CMSClassUnloadingEnabled 激活了)。
CMSIncrementalMode:使用增量模式,比較適合單 CPU。
UseCMSCompactAtFullCollection參數可使 CMS 在垃圾收集完成後,進行一次內存碎片整理。內存碎片的整理並非併發進行的。
UseFullGCsBeforeCompaction:設定進行多少次 CMS 垃圾回收後,進行一次內存壓縮。
一些建議
對於Native Memory:
因爲Native Memory只能經過FullGC回收,因此除非你很是清楚這時真的有必要,不然不要輕易調用System.gc()。
另外爲了防止某些框架中的System.gc調用(例如NIO框架、Java RMI),建議在啓動參數中加上-XX:+DisableExplicitGC來禁用顯式GC。這個參數有個巨大的坑,若是你禁用了System.gc(),那麼上面的3種場景下的內存就沒法回收,可能形成OOM,若是你使用了CMS GC,那麼能夠用這個參數替代:-XX:+ExplicitGCInvokesConcurrent。
此外除了CMS的GC,其實其餘針對old gen的回收器都會在對old gen回收的同時回收young gen。
G1收集器
G1收集器是一款面向服務端應用的垃圾收集器。HotSpot團隊賦予它的使命是在將來替換掉JDK1.5中發佈的CMS收集器。與其餘GC收集器相比,G1具有以下特色:
-
並行與併發:G1能更充分的利用CPU,多核環境下的硬件優點來縮短stop the world的停頓時間。
-
分代收集:和其餘收集器同樣,分代的概念在G1中依然存在,不過G1不須要其餘的垃圾回收器的配合就能夠獨自管理整個GC堆。
-
空間整合:G1收集器有利於程序長時間運行,分配大對象時不會沒法獲得連續的空間而提早觸發一次GC。
-
可預測的非停頓:這是G1相對於CMS的另外一大優點,下降停頓時間是G1和CMS共同的關注點,能讓使用者明確指定在一個長度爲M毫秒的時間片斷內,消耗在垃圾收集上的時間不得超過N毫秒。
在使用G1收集器時,Java堆的內存佈局和其餘收集器有很大的差異,它將這個Java堆分爲多個大小相等的獨立區域,雖然還保留新生代和老年代的概念,可是新生代和老年代再也不是物理隔離的了,它們都是一部分Region(不須要連續)的集合。
雖然G1看起來有不少優勢,實際上CMS仍是主流。
與GC相關的經常使用參數
除了上面說起的一些參數,下面補充一些和GC相關的經常使用參數:
-
-Xmx: 設置堆內存的最大值。
-
-Xms: 設置堆內存的初始值。
-
-Xmn: 設置新生代的大小。
-
-Xss: 設置棧的大小。
-
-PretenureSizeThreshold: 直接晉升到老年代的對象大小,設置這個參數後,大於這個參數的對象將直接在老年代分配。
-
-MaxTenuringThrehold: 晉升到老年代的對象年齡。每一個對象在堅持過一次Minor GC以後,年齡就會加1,當超過這個參數值時就進入老年代。
-
-UseAdaptiveSizePolicy: 在這種模式下,新生代的大小、eden 和 survivor 的比例、晉升老年代的對象年齡等參數會被自動調整,以達到在堆大小、吞吐量和停頓時間之間的平衡點。在手工調優比較困難的場合,能夠直接使用這種自適應的方式,僅指定虛擬機的最大堆、目標的吞吐量 (GCTimeRatio) 和停頓時間 (MaxGCPauseMills),讓虛擬機本身完成調優工做。
- -SurvivorRattio: 新生代Eden區域與Survivor區域的容量比值,默認爲8,表明Eden: Suvivor= 8: 1。
- -XX:ParallelGCThreads:設置用於垃圾回收的線程數。一般狀況下能夠和 CPU 數量相等。但在 CPU 數量比較多的狀況下,設置相對較小的數值也是合理的。
- -XX:MaxGCPauseMills:設置最大垃圾收集停頓時間。它的值是一個大於 0 的整數。收集器在工做時,會調整 Java 堆大小或者其餘一些參數,儘量地把停頓時間控制在 MaxGCPauseMills 之內。
- -XX:GCTimeRatio:設置吞吐量大小,它的值是一個 0-100 之間的整數。假設 GCTimeRatio 的值爲 n,那麼系統將花費不超過 1/(1+n) 的時間用於垃圾收集。