1. 程式人生 > >JVM 垃圾收集器Serial +Serial Old+ParNew+Parallel Scavenge+Parallel Old+CMS+G1

JVM 垃圾收集器Serial +Serial Old+ParNew+Parallel Scavenge+Parallel Old+CMS+G1

這裡寫圖片描述

 

1 Seiral 收集器

特徵

  1. 是單執行緒的
  2. 在垃圾回收時,必須暫停其他所有執行緒的工作執行緒,即所謂的“Stop The World”
  3. jvm在Client模式下,預設的新生代收集器仍然是Serial收集器,雖然它有著上述兩個重大的缺點,但也有這簡單高效的優點。
    1. 單執行緒,沒有執行緒互動開銷
  4. 使用方法:-XX:+UseSerialGC
  5. 適用:執行在Client模式下的虛擬機器。

 

Serial和Serial Old的協同工作模式

這裡寫圖片描述

2 Serial Old收集器

特徵

  • Serial Old是單執行緒,使用標記整理演算法Serial老年代版本,主要意義也是在於給Client模式下的虛擬機器使用。

  • Server模式下用途:
    • 在JDK1.5以及之前的版本中與Parallel Scavenge收集器搭配使用
    • 當老年代使用CMS收集器出現故障時(Concurrent Mode Failure),可以作為CMS的後備選擇。 

 

Serial和Serial Old的協同工作模式

這裡寫圖片描述

 

3 ParNew 收集器

 

特徵

  1. 其實就是Serial收集器的多執行緒版本,除了使用多條執行緒進行垃圾收集之外,其餘的和Serial所有控制引數一樣。
  2. 在配置為CMS 收集器的預設新生代收集器。
  3. 在多CPU的環境下可以發揮更高而效率,並且是唯一一個可以和CMS收集器搭配工作的新生代並行GC。
  4. 單CPU的環境下效率低於Serial
  5. 適用:執行在server模式下的虛擬機器首選的新生代收集器。
  6. 使用方法:-XX:+UseParNewGC

這裡寫圖片描述

 

Parallel Scavenge(並行回收)收集器

特徵

  1. 新生代收集器
  2. 使用複製演算法,並行的多執行緒收集器
  3. 控制的吞吐量
    1. 吞吐量=執行使用者程式碼時間/(執行使用者程式碼時間+垃圾收集時間)
  4. 停頓時間越短就越適合需要與使用者互動的程式,良好的響應速度能提升使用者體驗,而高吞吐量則可用高效率地利用CPU時間,儘快完成程式的運算任務,主要適合在後臺運算而不需要太多互動的任務。

  5. 引數:

    1. -XX:MaxGCPauseMillis:控制最大垃圾收起停頓時間(毫秒)。

      1. 收集器會盡可能的保證每次垃圾收集耗費的時間不超過這個設定值。但是如果這個這個值設定的過小,那麼Parallel Scavenge收集器為了保證每次垃圾收集的時間不超過這個限定值,會導致垃圾收集的次數增加和增加年輕代的空間大小,垃圾收集的吞吐量也會隨之下降。

      2. 注意: XX:MaxGCPauseMillis設定的越小,吞吐量則必然越小。

    2. -XX:GCTimeRatio: 設定吞吐量大小(>0,<100)。預設值為99,即最大允許1%的垃圾收集時間。

      1. 是應用程式執行時間和垃圾收集時間的比值。如果把值設定為19,即系統執行時間 : GC收集時間 = 19 : 1,那麼GC收集時間就佔用了總時間的5%【1 / (19 + 1) = 5%】,

    3. -XX:+UseAdaptiveSizePolicy:

      1. 當這個引數開啟之後,就不需要手工指定新生代的大小、Eden與Survivor區的比例、晉升老年代物件年齡等細節引數了,虛擬機器會根據當前系統的執行情況收集效能監控資訊,動態調整這些引數以提供最合適的停頓時間或者最大的吞吐量,這種調節方式稱為GC自適應的調節策略(GC Ergonomics)。

      2. 只需要把基本的記憶體資料設定好(如-Xmx設定最大堆),然後使用MaxGVPauseMillis引數或GCTimeRation引數給虛擬機器設立一個優化目標,JVM會自動調節其他優化引數.

      3. 自適應調節策略也是Parallel Scavenge收集器與ParNew收集器的一個重要區別

  6. Parallel Scavenge要和Parallel Old一起使用

Parallel Scavenge/Parallel Old執行示意圖

這裡寫圖片描述

5 Parallel Old 收集器

特徵

  1. 是Parallel Scavenge收集器的老年代版本,使用多執行緒和“標記-整理”演算法。
  2. 引數控制: -XX:+UseParallelOldGC 
  3. 只能和Parallel Scavenge配合使用,這個組合常用於注重吞吐量以及CPU資源敏感的場合。 

 

Parallel Scavenge/Parallel Old執行示意圖

這裡寫圖片描述

 

 

6 CMS(Concurrent Mark Sweep)收集器

特徵

  1. 一種以獲取最短回收停頓時間為目標的收集器。

  2. 適用於 :重視服務的響應速度,希望系統停頓時間最短,以給使用者帶來較好的體驗的應用。

  3. CMS收集器是基於“標記-清除”演算法實現的,

  4. 運作過程分為4個步驟:

    1. 初始標記(CMS initial mark)
      1. 需要“Stop The World”,僅僅只是標記一下GC Roots能直接關聯到的物件,速度很快。
    2. 併發標記(CMS concurrent mark)

      1. 就是進行GC Roots Tracing(跟蹤)的過程。(就是判斷哪些物件不可達的過程)。

      2. 與使用者執行緒一起工作。

    3. 重新標記(CMS remark)

      1. 需要“Stop The World”,是為了修正併發標記期間,因使用者程式繼續運作而導致標記產生變動的那一部分物件的標記記錄,這個階段的停頓時間一般會比初始標記階段稍長一些,但遠比並發標記的時間短。

    4. 併發清除(CMS concurrent sweep)

      1. 與使用者執行緒一起工作。

  5.  總體上來說,CMS收集器的記憶體回收過程是與使用者執行緒一起併發地執行。 

  6.  

     優點:併發收集、低停頓。

  7.  缺點:
    1. CMS收集器對CPU資源非常敏感。對於併發實現的收集器而言,雖然可以利用多核優勢提高垃圾收集的效率,但是由於收集器在執行過程中會佔用一部分的執行緒,這些執行緒會佔用CPU資源,所以會影響到應用系統的執行,會導致系統總的吞吐量降低。CMS預設開始的回收執行緒數是(cpu數量 + 3) / 4,所以,當機器的CPU數量為4個以上的時候,垃圾回收執行緒將佔用不少於%25的CPU資源,並且隨著CPU數量的增加,垃圾回收執行緒佔用的CPU資源會減少。但是,當CPU資源少於4個的時候,垃圾回收執行緒佔用的CPU資源的比例會增大,會影響到系統的執行,假設有2個CPU的情況下,垃圾回收執行緒將會佔據超過50%的CPU資源。所以,在選用CMS收集器的時候,需要考慮,當前的應用系統,是否對CPU資源敏感。

    2. 垃圾收集的過程中,無法處理浮動垃圾,所以可能會出現Concurrent Mode Failure問題而導致觸發一次Full GC。浮動垃圾:是由於CMS收集器的併發清理階段,清理執行緒是和使用者執行緒一起執行,如果在清理過程中,使用者執行緒產生了垃圾物件,由於過了標記階段,所以這些垃圾物件就成為了浮動垃圾,CMS無法在當前垃圾收集過程中集中處理這些垃圾物件。由於這個原因,CMS收集器不能像其他收集器那樣等到完全填滿了老年代以後才進行垃圾收集,需要預留一部分空間來保證當出現浮動垃圾的時候可以有空間存放這些垃圾物件。在JDK 1.5中,預設當老年代使用了68%的時候會啟用垃圾收集,這是一個保守的設定,如果在應用中老年代增長不是很快,可以通過引數 -XX:CMSInitiatingOccupancyFraction 控制觸發的百分比,以便降低記憶體回收次數來提供效能。在JDK 1.6中,CMS收集器的啟用閥值變成了92%。如果在CMS執行期間沒有足夠的記憶體來存放浮動垃圾,那麼就會導致Concurrent Mode Failure失敗,這個時候,虛擬機器將啟動後備預案,臨時啟動Serial Old收集器來對老年代重新進行垃圾收集,這樣會導致垃圾收集的時間邊長,特別是當老年代記憶體很大的時候。所以對引數-XX:CMSInitiatingOccupancyFraction的設定,過高,會導致發生Concurrent Mode Failure,過低,則浪費記憶體空間。

    3. 使用的"標記-清除"演算法會出現很多記憶體碎片。過多的記憶體碎片會影響大物件的分配,會導致即使老年代記憶體還有很多空閒,但是由於過多的記憶體碎片,不得不提前觸發垃圾Full GC。為了解決這個問題,CMS收集器提供了一個"-XX:+UseCMSCompactAtFullCollection"引數(預設是開啟的),用於CMS收集器在必要的時候對記憶體碎片進行壓縮整理。由於記憶體碎片整理過程不是併發的,所以會導致停頓時間變長。虛擬機器還提供了一個-XX:CMSFullGCsBeforeCompaction"引數,來控制進行過多少次不壓縮的Full GC以後,進行一次帶壓縮的Full GC,預設值是0,表示每次在進行Full GC前都進行碎片整理。

  8.  引數
    1. -XX:+UseConcMarkSweepGC:使用CMS收集器
    2.  -XX:+ UseCMSCompactAtFullCollection: Full GC後,進行一次碎片整理;整理過程是獨佔的,會引起停頓時間變長。 
    3. -XX:+CMSFullGCsBeforeCompaction  設定進行幾次Full GC後,進行一次碎片整理。
    4. -XX:ParallelCMSThreads  設定CMS的執行緒數量(一般情況約等於可用CPU數量) 。

CMS收集器示意圖
這裡寫圖片描述

 

7G1收集器(面向服務端)

 特點:

  1. 並行於併發:使用多個CPU(CPU或者CPU核心)來縮短stop-The-World停頓時間,其他需要停頓Java執行緒執行的GC動作,G1收集器仍然可以通過併發的方式讓java程式繼續執行。
  2. 分代收集:雖然G1可以不需要其他收集器配合就能獨立管理整個GC堆,但是還是保留了分代的概念。它能夠採用不同的方式去處理新建立的物件和已經存活了一段時間,熬過多次GC的舊物件以獲取更好的收集效果。
  3. 空間整合:與CMS的“標記--清理”演算法不同,G1從整體來看是基於“標記整理”演算法實現的收集器;從區域性上來看是基於“複製”演算法實現的。但無論如何,都意味著G1運作期間不會產生記憶體空間碎片,收集後能夠提供規整的可用記憶體,這種特性有利於程式長時間執行,分配大物件時不會因為無法找到連續記憶體空間而提前觸發下一次GC。
  4. 可預測的停頓:這是G1相對於CMS的另一大優勢,降低停頓時間是G1和CMS共同關注點, 但G1除了追求低停頓外,還能建立可預測的停頓時間模型,能讓使用者明確指定在一個長度為M毫秒的時間片段內,消耗在垃圾收集上的時間不得超過N毫秒。

 儲存記憶體結構

 
G1會將堆劃分為固定大小的多個區域,名稱為Region,每一個Region都有對應一個remembered set(避免全堆掃描,記錄每個物件是否可達),依然存在eden,S0,S1,old這些概念,不同的是是採用邏輯區分,而不是物理區分.每個heap區(Region)的大小在JVM啟動時就確定了. JVM 通常生成 2000 個左右的heap區, 根據堆記憶體的總大小,一個Region的大小可以通過引數-XX:G1HeapRegionSize設定,範圍允許為 1Mb 到 32Mb,且是2的指數倍。

這裡寫圖片描述

優先列表

 G1跟蹤各個region裡面的垃圾堆積的價值大小(回收所獲得的空間大小以及回收所需時間的經驗值),在後臺維護一個優先列表,每次根據允許的收集時間,優先回收價值最大的Region。這種使用Region劃分記憶體空間以及有優先順序的區域回收方式,保證了G1收集器在有限的時間內可以獲取儘可能高的收集效率。
 

執行示意圖

這裡寫圖片描述

 

收集步驟:

1、標記標記(Initial Marking):停頓使用者,耗時很短,只是標記一下GC Roots能直接關聯到的物件,並且修改TAMS(Next Top At Mark Start)的值,讓下一個階段使用者程式併發執行時,能在正確可用的Region中建立新物件。

2 併發標記(Concurrent Marking):GC Root開始對堆中物件進行可達性分析,找出存活的物件,這階段時耗時較長,但可與使用者程式併發執行。

3終標記階(Final Marking): 為了修正在併發標記期間因使用者程式繼續運作而導致標記產生變動的那一部分標記記錄,虛擬機器將這段時間物件變化記錄線上程Remenbered Set Logs裡面,最終標記階段需要把Remembered Set Logs的資料合併到Remembered Set中,這一階段需要停頓執行緒,但是可並行執行。

4 篩選回收:首先對各個Region的回收價值和成本進行排序,根據使用者所期望的GC停頓時間來制定回收計劃。