垃圾收集器就是使用一種或者多種垃圾回收算法,在不一樣的內存分配策略下,進行垃圾回收的程序。因爲內存分配策略不一樣的緣由,因此垃圾回收算法以及垃圾收集器的種類也不盡相同,下圖是JDK1.7 Update 14以後的HotSpot虛擬機所包含的全部的垃圾收集器。java
HotSpot中的收集器分類算法
圖上整體分爲兩大類,年輕代(Young generation)和老年代(Tenured generation)。上圖中的連線表示在年輕代和老年代之間,哪些收集器能夠兩兩配合使用,「八字不合」的收集器是不能在一塊兒的!注意到,G1收集器是當前最前沿的收集器,它不須要和其餘收集器配合,本身就能完成年輕代和老年代的垃圾回收工做。多線程
1.Serial收集器併發
Serial收集器應該算是收集器家族中元老級的任務,它是一款歷史比較悠久的收集器,在JDK1.3以前仍是新生代收集器的惟一選擇。Serial的中文意思是「串行」,也就是說他是一個單線程工做的垃圾收集器,其全部的工做都是在單個線程單個CPU的狀況下完成的。除了單線程以外,Serial收集器在進行垃圾回收的過程當中,須要暫停其餘全部的用戶線程,JAVA專家稱這種狀況爲:「Stop The World」。這種好比真的是再形象不過了,由於在那一刻真的好像世界都中止了。有人舉過一個形象的例子,你女友在給你打掃放假的時候,確定不會讓你再處處亂跑,若是她一邊打掃,你一邊亂跑,極可能晚上就要睡沙發了。實際上,「Stop The world」致使的停頓現象,即使是如今的最新的G1垃圾收集器也不可能說徹底避免,而只能不斷地縮短Stop The World的時間。佈局
經過上面的介紹,你們可能以爲Serial收集器多是一個又老又慢過期的收集器,估計已經被淘汰了。然而事實上並不是如此,它到目前爲止依賴是虛擬機運行在client模式下的默認年輕代收集器。咱們先來看一下Serial收集器的工做的過程,以後能夠和後面的幾個收集器在進行對比,就能發現Serial收集器在某些特殊的環境下,仍是有優勢的:性能
Serial/Serial Old收集器回收過程優化
正式由於Serial的單線程,因此它相比於其餘的收集器來講,優勢就是簡單而高效,對於單個CPU的環境的來講,Serial收集器沒有線程交互,因此回收的效率相對來講就比較高。因此Serial收集器更適合運行在client模式下的虛擬機,如桌面應用等。ui
關於JVM Client模式和Server模式:Client模式採用的是輕量級的虛擬機,全部啓動的比較快;Server模式採用的是重量級的虛擬機,因此啓動比較慢。重量級的虛擬機在運行期間作了不少的優化,因此啓動以後程序運行比較快。Client模式通常內存佔用的狀況比較小,VM在client模式默認-Xms是1M,-Xmx是64M;JVM在Server模式默認-Xms是128M,-Xmx是1024M;因此Client在進行Stop The World的時間相對來講不會太長,因此使用簡單快速的Serial收集器來進行垃圾回收時再合適不過的了。線程
2.ParNew收集器設計
ParNew名字前面的Paral其實是單詞「parallel」的縮寫,意思是並行。因此從名字就能夠知道ParNew收集器應該是多線程,事實上它就是Serial收集器的多線程的版本,因此,它除了是多線程的以外,其餘的全部的東西像控制參數、收集算法、Stop The World、對象分配規則、回收策略等都與Serial收集器徹底同樣。ParalNew收集器回收過程以下圖所示:
ParNew / Seria Old收集器回收過程
ParNew收集器相對於Serial收集器除了多線程以外,並無其餘的特色。因此若是在單CPU的狀況下,ParalNew收集器並不會比Serial的性能好,甚至由於存在線程的交互的開銷,ParalNew性能反而更差。另外就是,在JDK1.5時期推出了CMS(Concurrent Mark Sweep),這個幾乎被認爲有劃時代意義的垃圾收集真正實現了垃圾回收的併發操做,也就是用戶線程和GC線程是同時工做的。可是你們從開頭的分類圖上能夠看出,在新生代中,能夠和CMS同時工做的只有Serial和ParNew能夠與之搭配工做。因此,在多核的環境下,ParNew收集器是最佳的選擇。
3.Parallel Scavenge收集器
Parallel Scavenge收集器是一個新生代收集器,它也是使用了複製算法的收集器(前面介紹的兩種收集器都是複製算法),並且又是並行的多線程收集器,看起來好像和ParNew收集器沒什麼不一樣。哲學上常說,存在便是合理的,一件東西不會無緣無故的出現,Parallel Scavenge也是同樣,那麼它到底有什麼神奇之處呢?
Parallel Scavenge收集器的特色是它的關注點和其餘的收集器不同,CMS收集器的關注點是儘量是縮短垃圾回收時用戶線程的停頓時間,而Parallel收集器的目標則是達到一個可控制的吞吐量。所謂吞吐量就是CPU用於運行用戶代碼的時間與CPU總消耗時間的比值:
停頓時間越短越適合與用戶交互的程序,由於與用戶交互的程序須要有良好的響應速度來提高用戶的體驗。也就是說,在一系列的用戶操做中,用戶並不但願出現長久停頓的狀況。就比如你正在看某種大片,過程當中每隔一段時間就停頓一下,你確定很不爽。假如這個停頓的時間就是垃圾回收致使的,因此你固然但願這個停頓的時間越短越好。Parallel Scavenge就是用來將吞吐量控制在一個能夠接受的範圍內。Parallel Scavenge提供幾個參數來精確控制吞吐量:
參數 |
參數描述 |
-XX:MaxGCPauseMillis |
該參數容許設置一個大於0的毫秒數,收集器將盡量地保證 內存花費的時間不超過該值 |
-XX:GCTimeRatio |
該參數容許設置一個0~100之間的整數,也就是垃圾收集時間佔用比,至關於吞吐量的倒數 |
-XX:+UseAdaptiveSizePolicy |
該參數是一個開關參數,打開以後就不須要制定新生代的大小(-Xmm),Eden與Suirvive的比例(-XX:SurvivorRatio)、晉升老年代對象大小(-XX:PreTenureSizeThreshold)等細節參數了,虛擬機會根據系統運行狀況,動態調整這些參數 |
注意:雖然Paralle Scavenge的參數是能夠精確控制程序運行的吞吐量的,可是並非GC停頓時間控制越小越好。由於GC停頓時間變短,是以犧牲GC吞吐量和新生代空間來換取的。也就是說,太小的GC停頓時間會致使更頻繁地發生GC。因此,Paralle Scavenge參數要設置在一個合理的範圍內,才能讓系統更好的運行。若是對於這方面沒有經驗的人,可使用參數3,讓系統本身決定吞吐量。
4.Serial Old收集器
Serial Old收集器相至關於Serial收集器的老年代版本,使用的是標記-整理的算法,一樣他是一個單線程的收集器。如今這個收集器的主要做用就是在Client模式下,做爲虛擬機老年代的回收的垃圾收集器使用。可是若是你要把用在Server模式中,他就具有下面兩種用途:
Serial Old收集器的工做過程以下圖所示:
ParNew / Seria Old收集器回收過程
5.Parallel Old收集器
Parallel Old是Parallel Scavenge收集器的老年代版本,使用的是多線程和標記-整理。這個算法是在JDK1.6以後才提供的,因此Serial Old才能夠做爲Parallel Scavenge收集器Jdk1.5以前的年輕代收集器配合使用。因此在JDK1.6出現以前,Parallel Scavenge收集器是比較尷尬的,一方面本身在年輕代中使用的是多線程的,而在老年代中,只有單線程的Serial Old能夠選擇。因此在Parallel Old收集器出現以前,Parallel Scavenge收集器的地位是十分尷尬的。因爲在老年代中Serial Old的效率拖後腿,因此Parallel Scavenge收集器一直處於一種不給力的狀態。
直到Parallel Old收集器出現以後,「吞吐量優先」纔有了比較名副其實的應用組合,因此JDk1.6以後,在注重吞吐量以及CPU資源敏感的場景中,均可以優先考慮Parallel Scavenge加Parallel Old的組合。他們組合的垃圾回收過程以下圖所示:
Parallel Scavenge / Parallel Old收集器回收過程
5.CMS收集器(Concurrent Mark Sweep)
CMS收集器的目標是以得到最短回收停頓時間爲目標的收集器(注意和Parallel Old收集器加以區分,Parallel Old是目標是精確控制程序運行的吞吐量,即停頓時間可控制)。從名稱上咱們能夠看出來CMS使用的標記-清除的算法,它的運行過程相對來講比較複雜,整個過程能夠分爲4個步驟:
咱們能夠先來看一下CMS收集器的垃圾回收過程,以下圖所示:
CMS垃圾回收過程
從圖上能夠看出,在初始標記和從新標記這兩個階段仍然須要"Stop The World"。初始標記只是標記一下GC Roots能直接關聯到的對象,速度很快。併發標記的階段就是進行GC Roots Tracing的過程,而從新標記的過程就是爲了修正併發標記期間由於用戶程序仍然運行而致使變更的那一部分對象的標記記錄。這個過程當中的時間要比初始標記長一些,可是要遠比並發標記的時間要短。因此CMS把標記階段能夠大體理解爲兩個階段,一個階段是能夠併發標記的階段,不會影響程序運行;另外一個階段就是不能夠併發標記的階段,就是標記過程會影響程序運行,因此這個階段要「Stop The World」。可是由於大部分標記工做已經在第一個階段完成,因此第二部分的時間就很是短。相比於以前的收集器不加以區分的方式,這種方式能夠大大減小由於標記而致使「Stop The World」停頓的時間。
從設計來講,CMS使用的也是多線程的方式來進行垃圾回收,因爲是和用戶線程同時進行,且使用的標記-清除算法,因此它就存在如下三個明顯的缺點:
5.G1收集器(Garbage First)
G1是一款面向服務端應用的垃圾收集器,HotSpot團隊的目標是,在將來能夠用G1替換掉JDK1.5中發佈的CMS收集器。與其餘的收集器相比,G1收集器具備以下特色:
在G1以前的其餘收集器進行瘦的範圍都是整個新生代和老年代,G1收集器java堆的內存佈局與其餘收集器有很大的差異,他將整個java堆分爲多個大小相等的獨立區域(Region),雖然還保留有新生代和老年代的概念,但新生代和老年代再也不是物理隔離的了,他們都是一部分Region(不須要連續)的集合。
G1的詳解講解會做爲新的一章來分析,以上關於G1的描述摘抄子(深刻了解虛擬機),後面會有單獨的一章來說G1收集器。