若是說收集算法是內存回收的方法論,那麼垃圾收集器就是內存回收的具體實現。java虛擬機規範中對垃圾收集器應該如何實現並無任何規定,所以不一樣的廠商、不一樣的版本的虛擬機所提供的垃圾收集器都有可能會有很大的區別,而且通常都會提供參數供用戶根據本身的應用特色和要求組合出各個年代所使用的收集器。html
相關係列博客:java
上圖中展現了不一樣年齡代的收集器,其中Serial、ParNew和Parallel Scavenge收集器做用於新生代,CMS、Parallel Old 和 Serial Old做用於老年代,G1在新生代和老年代均可以使用。不一樣的收集器之間若是有連線,則說明他們能夠相互搭配使用。算法
並行:指的是多條垃圾收集線程一塊兒公共,可是此時用戶工做線程仍處於等待狀態。多線程
併發:指的是用戶線程和垃圾收集線程同時工做,也有多是交替執行,用戶程序在繼續執行,而垃圾收集程序運行與另外一個CPU上。併發
吞吐量:吞吐量就是CPU用於運行用戶代碼的時間與CPU總消耗時間的比值,即吞吐量 = 運行用戶代碼時間 /(運行用戶代碼時間 + 垃圾收集時間)。虛擬機總共運行了100分鐘,其中垃圾收集花掉1分鐘,那吞吐量就是99%。post
Serial收集器是一款串行執行的收集器,它是歷史最悠久,也是最基本的收集器,採用複製算法實現的新生代收集器。在jdk1.3之前,Serial收集器是新生代惟一的選擇。它是一個單線程執行的收集器,工做時只會知用一個cpu或線程區執行,更重要的是Serial在工做期間必須停掉全部的用戶線程,直至垃圾收集完成,這一過程咱們稱之爲「stop the world」。這項工做是由虛擬機自動執行和自動完成的,用戶在不知情的狀況下停掉了全部的線程,這對於一個最求響應速度來講簡直是沒法接受的。下圖展現了Serial收集器在工做時的運行流程:性能
因爲Serial收集器的工做模式是單線程的,天然就沒有了多線程環境下線程切換帶來的性能開銷,因此該收集器在單線程環境下更加簡單高效。網站
Parnew是Serial收集器的多線程版本,也是新生代收集器。ParNew收集器和Serial收集器除了多線程工做外幾乎是相同的,包括全部控制參數、收集算法、stop the world,對象分配規則,回收策略等都是同樣的。運行流程以下圖:url
雖然與Serial收集器相比僅僅多了多線程特性外,沒有其它的創新之處,可是它倒是許多Server模式下的虛擬機新生代收集器的首選,緣由在於目前爲止只有Serial和ParNew兩個新生代收集器可以與性能優異的CMS配合使用。關於CMS介紹將在下文展開描述。線程
Parallel Scavenge也是一款使用複製算法的新生代收集器。該收集器與其它收集器不一樣的是,它關注的目標是達到一個可控制的吞吐量,而CMS等收集器的關注點則是儘量地減小用戶線程地停頓時間,提升用戶體驗。Parallel Scavenge收集器提供了兩個參數用於精確控制吞吐量,分別是控制最大垃圾收集停頓時間的-XX:MaxGCPauseMillis參數以及直接設置吞吐量大小的-XX:GCTimeRatio參數。也所以,Parallel Scavenge 被成爲「吞吐量優先」收集器。
停頓時間越短就越適合與用戶交互較多地程序,這樣用戶體驗才更好。而高吞吐量則可讓出更多的cpu資源給用戶線程,讓程序更快的完成運算任務,更適合後臺運算較多而不須要與用戶交互的程序。
自適應調節策略是Parallel Scavenge收集器的特色,也是與ParNew收集器的區別。Parallel Scavenge經過打開-XX:+UseAdaptiveSizePolicy的設置,就不須要手動地調節新生代(-Xmn)大小,Eden和Survivor區的比例(-XX:SurvivorRatio)、晉升老年代對象年齡(-XX:PretenureSizeThreshold)等細節參數,而是根據當前系統運行狀況來肯定這些參數,從而提升程序地吞吐量和縮短停頓時間,這一過程稱之爲GC自適應的調節策略(GC Ergonomics)。
另外值得注意的一點是,Parallel Scavenge沒法已CMS配合使用,若是新生代選擇了Parallel Scavenge收集器,那麼老年代的收集器只能選用Serial Old或者Parallel Old來配置使用。
Serial Old是Serial收集器的老年代版本,也是單線程工做的,使用的是「標記-整理」算法。
該收集器主要用於Client模式下的虛擬機使用,若是在Server模式下能夠與Parallel Scavenge收集器配合使用;做爲CMS收集器的後備預案,在併發收集發生Concurrent Mode Failure時使用。運行流程以下:
Parallel Old是Parallel Scavenge的老年代版本,也是一個並行收集器,使用「標記-整理」算法。該收集器在jdk1.6後對外提供使用,Parallel Scavenge 和 Parallel Old配合使用的話,更加適合應用於高吞吐量和cpu敏感資源的場合。下面是這兩個收集器配合使用的運行流程:
CMS(Concurrent Mark Sweep)是一個併發收集器,使用了「標記-清除」算法來實現的。該收集器最求的更短的停頓時間,從而提高用戶體驗,所以也很是符合使用在網站、B/S系統的服務端的應用。
CMS收集器的工做流程大概能夠分爲如下4個步驟:
因爲標記和清除階段能夠和用戶線程一塊兒工做,所以幾乎能夠把CMS收集器的工做是併發的:
CMS是一款優秀的收集器,它的主要優勢是低停頓,併發收集,所以也被成爲併發低停頓收集器(Concurrent Low Pause Collector)。
固然,CMS收集器也有必定的缺點,主要包括一下幾點:
運行示意圖以下:
G1(Garbage-First)是一款面向服務端應用的垃圾收集器,JDK 7 Update4 後開始進入商用。HotSpot開發團隊賦予它的使命是將來能夠替換掉JDK 1.5中發佈的CMS收集器。以前提供的收集器都是僅做用於新生代或者是老年代,可是G1收集器能夠做用於新生代和老年代,由於使用G1收集器是java heap的內存結構有很大的不一樣,它將整個Java堆劃分爲多個大小相等的獨立區域(Region),雖然還保留有新生代和老年代的概念,可是他們已經沒有了物理上的隔閡了,它們都是region的一部分的集合。
G1(Garbage-First)收集器是當今收集器技術發展的最前沿成果之一,與其餘收集器相比,G1收集器具備如下特徵:
G1收集器之因此可以創建可預測的停頓時間模型,由於他可以有計劃地避免在整個Java堆中進行全區域的垃圾收集。G1跟蹤各個Region裏面的垃圾堆積的價值大小(回收所得到的空間大小以及回收所須要的經驗值),在後臺維護一個優先表,每次根據容許的收集時間,優先回收價值最大的Region。這種使用Region劃份內存空間以及有優先級的區域回收方式,保證了G1收集器在有限的時間內能夠獲取儘量高的收集效率。
在G1收集器中,Region之間的對象引用以及其餘收集器中的新生代和老年代之間的對象引用,虛擬機都是使用Remembered Set來避免全堆掃描的。G1中每一個Region都有一個與之對應的Remembered Set,虛擬機發現程序在對Reference類型的數據進行寫操做時,會產生一個Write Barrier暫時中斷寫操做,檢查Reference引用的對象是否處於不一樣的Region中,若是是,便經過CardTable把相關引用信息記錄到被引用對象所屬的Region中的Remembered Set之中。當進行內存回收時,在GC根節點的枚舉範圍中加入Remembered Set便可保證不對全堆掃描,也不會有遺漏。
若是不計算維護Remembered Set的操做,G1收集器的運做大體分爲如下幾個步驟:
執行流程以下圖:
收集器 | 串行、並行or併發 | 新生代/老年代 | 算法 | 目標 | 適用場景 |
---|---|---|---|---|---|
Serial | 串行 | 新生代 | 複製算法 | 響應速度優先 | 單CPU環境下的Client模式 |
Serial Old | 串行 | 老年代 | 標記-整理 | 響應速度優先 | 單CPU環境下的Client模式、CMS的後備預案 |
ParNew | 並行 | 新生代 | 複製算法 | 響應速度優先 | 多CPU環境時在Server模式下與CMS配合 |
Parallel Scavenge | 並行 | 新生代 | 複製算法 | 吞吐量優先 | 在後臺運算而不須要太多交互的任務 |
Parallel Old | 並行 | 老年代 | 標記-整理 | 吞吐量優先 | 在後臺運算而不須要太多交互的任務 |
CMS | 併發 | 老年代 | 標記-清除 | 響應速度優先 | 集中在互聯網站或B/S系統服務端上的Java應用 |
G1 | 併發 | both | 標記-整理+複製算法 | 響應速度優先 | 面向服務端應用,未來替換CMS |
參考資料: 《深刻理解Java虛擬機-JVM高級特性與最佳實踐》 -周志明
喜歡我寫的博客的同窗能夠關注訂閱號【Java解憂雜貨鋪】,裏面不按期發佈一些技術幹活,也能夠免費獲取大量最新最流行的技術教學視頻