JVM垃圾收集器

原文地址:xeblog.cn/articles/24java

image

新生代收集器

新生代均採用 複製 算法來回收內存。算法

Serial 收集器

最基本的、發展歷史最悠久的單線程的收集器。在進行垃圾收集時,必須暫停其它全部的工做線程(Stop The World),直到它收集結束。它是 JVM 運行在 Client 模式下的默認新生代收集器,它比其它單線程的收集器更簡單、更高效。可與 CMS 收集器 配合工做。bash

ParNew 收集器

Serial 收集器 的多線程版本。它是許多運行在 Server 模式下的虛擬機首選的新生代收集器,在使用 -XX:+UseConcMarkSweepGC 選項後的默認新生代收集器,也能夠經過 -XX:+UseParNewGC 選項強制指定它。它除了是多線程收集以外,其它和 Serial 收集器 基本同樣,它默認開啓的收集線程數與 CPU 的數量相同,在 CPU 很是多的環境下,可經過 -XX:ParallelGCThreads 參數限制垃圾收集的線程數。可與 CMS 收集器 配合工做。多線程

Parallel Scavenge 收集器

並行的多線程收集器,它的目標是達到一個可控的吞吐量(吞吐量是 CPU 用於運行用戶代碼的時間與 CPU 總消耗時間的比值)。併發

吞吐量 = 運行用戶代碼的時間 / (運行用戶代碼的時間 + 垃圾收集時間)
複製代碼

高吞吐量能夠高效的利用 CPU 時間,儘快的完成程序的運算任務,主要適合在後臺運算而不須要太多交互的任務。Parallel Scavenge 收集器 提供了兩個參數用於精確控制吞吐量: -XX:MaxGCPauseMillis-XX:GCTimeRatio性能

最大垃圾收集停頓時間:-XX:MaxGCPauseMillis

容許一個大於0的毫秒數,收集器將盡量保證內存回收花費時間不超過這個設定的值,它是以犧牲吞吐量和新生代空間來縮短 GC 停頓時間的。spa

吞吐量大小:-XX:GCTimeRatio

容許一個大於0且小於100的整數,垃圾收集時間佔總時間的比率。線程

GC自適應調節參數:-XX:+UseAdaptiveSizePolicy

這是一個開關參數,當它打開後,就不須要手動指定新生代的大小(-Xmn),EdenSurvivor 區的比例(-XX:SurvivorRatio)、晉升老年代對象年齡(-XX:PretenureSizeThreshold)等細節參數了,虛擬機會根據當前系統的運行狀況收集性能監控信息,動態調整這些參數以提供最合適的停頓時間或最大的吞吐量。3d

老年代收集器

老年代採用 標記-整理標記-清除 算法來回收內存。code

Serial Old 收集器

它是 Serial 收集器 的老年代版本,也是一個單線程收集器,使用 標記-整理 算法。這個收集器的主要意義也是在於給 Client 模式下的虛擬機使用,若是是在 Server 模式下,那麼它主要還有兩大用途:

  • JDK1.5 以及以前版本中與 Parallel Scavenge 收集器 搭配使用。
  • 做爲 CMS收集器 的後備預案,在併發收集發生 Concurrent Mode Failure 時使用。

Parallel Old 收集器

它是 Parallel Scavenge 收集器 的老年代版本,使用多線程和 標記-整理 算法。

CMS 收集器 (Concurrent Mark Sweep)

它是一種併發的、以獲取最短回收停頓時間爲目標的收集器,使用 標記-清除 算法實現的。運行過程較爲複雜,整個過程分爲4個步驟:

  • 初始標記(CMS Initial Marking)
  • 併發標記(CMS Concurrent marking)
  • 從新標記(CMS ReMarking)
  • 併發清除(CMS Concurrent Sweep)

初始標記、從新標記仍須要暫停其它全部的工做線程,初始標記僅僅只是標記一下 GC Roots  能直接關聯到的對象,速度很快。併發標記階段就是進行 GC Roots 的可達性分析過程,而從新標記階段則是爲了修正併發標記期間因用戶線程繼續運做而致使標記產生變更的那一部分對象的標記記錄,這個階段的停頓時間通常會比初始標記階段稍長一些,但遠比並發標記的時間短。CMS 收集器 存在3個明顯的缺點:

  • CMS收集器 會佔用一部分線程而致使應用程序變慢,總吞吐量會下降。CMS 默認啓功的回收線程數是(CPU數量 + 3)/ 4 ,至關於當 CPU 在4個以上時,併發回收時垃圾收集線程很多於 25%CPU 資源,並隨着 CPU 數量的增長而降低。當 CPU 不足4個時,CMS 對用戶線程的影響就可能變得更大。
  • CMS收集器 沒法處理浮動垃圾,可能出現 Concurrent Mode Failure 失敗而致使另外一次 Full GC 的產生。因爲 CMS 併發清除階段用戶線程還在運行着,伴隨程序運行天然就還會有新的垃圾不斷產生,這一部分垃圾出如今標記過程以後,CMS 沒法在當次收集中處理掉它們,只好留在下一次 GC 時再清理掉,這一部分垃圾就稱爲浮動垃圾。
  • 因爲 CMS收集器 使用的是 標記-清除 算法,因此垃圾回收後會產生大量的空間碎片。CMS 提供 -XX:+UseCMSCompactAtFullCollection 的開關參數(默認開啓),用於在 CMS 收集器頂不住要進行 Full GC 時開啓內存碎片的合併整理過程,這個過程是沒法併發執行的,雖然空間碎片沒了,可是停頓時間不得不變長。

全乾工程師:G1收集器

G1收集器 是當今收集器技術發展的最前沿成果之一。

上面所介紹的收集器,都只是負責 Java堆 中的一部份內存(新生代或老年代),而 G1 就不一樣了,它全乾。
G1 將整個 Java堆 劃分爲多個大小相等的獨立區域(Region),雖然還保留有新生代和老年代的概念,可是這兩部份內存再也不是物理隔離的,它們都是一部分不須要連續的 Region 的集合了。

具有的特色:

  • 並行與併發:G1 能充分利用多 CPU 、多核環境下的硬件優點,使用多個 CPU 來縮短 Stop The World 的停頓時間。
  • 分代收集(全乾工程師):G1 能夠不須要與其它收集器配合就能獨立管理整個 GC堆,根據 分代收集 的概念採用不一樣的方式去處理。
  • 空間整合:基於 標記-整理複製 算法,不會產生內存空間碎片。
  • 可預測的停頓:G1 能夠創建可預測的停頓時間模型,將垃圾收集消耗的時間限制在必定的時間內。

可預測的停頓時間模型

G1 之因此可以創建可預測的停頓時間模型,是由於它能夠有計劃的避免在整個 Java堆 中進行全區域的垃圾收集。G1 經過跟蹤各個 Region 裏面的內存堆積的價值大小(回收所得到的空間大小以及回收所需時間的經驗值),在後臺維護一個優先回收隊列,每次根據容許的收集時間,優先回收價值最大的 Region。這種使用 Region 劃份內存空間以及有優先級的區域回收方式,保證了 G1 收集器在有限的時間內能夠獲取儘量高的收集效率。

避免全堆掃描且保證準確性

G1 收集器中,Region 之間的對象引用以及其它收集器中的新生代與老年代之間的對象引用,虛擬機都是使用 Remembered Set 來避免全堆掃描的。G1 中的每個 Region 都有一個與之對應的 Remembered Set,在對 Reference 類型的數據進行寫操做的時間,虛擬機會產生一個屏障暫時中斷寫操做,而後檢查這個引用的對象是否處於不一樣的 Region 之中,若是是,就會經過 CardTable 把相關引用信息記錄到被引用對象所屬的 RegionRemembered Set 中。當進行內存回收時,在 GC Roots 的枚舉範圍內加入 Remembered Set 便可保證不對全堆掃描也不會有遺漏。

G1運行過程

若是不計算維護 Remembered Set 的操做,G1 收集器的運行過程大體能夠分爲4個步驟:

  • 初始標記(G1 Initial Marking)
  • 併發標記(G1 Concurrent Marking)
  • 最終標記(G1 Final Marking)
  • 篩選回收(G1 Live Data Counting And Evacuation)

初始標記階段只是簡單的標記一下 GC Roots  能直接關聯到的對象,而且修改TAMS(Next Top At Mark Start)的值,讓下一階段用戶程序併發運行時,能在正確可用的 Region 中建立新對象,這個階段須要停頓線程,但耗時很短。併發標記階段也是進行 GC Roots 的可達性分析過程,耗時很長可是可與用戶程序一塊兒工做。最終標記階段是爲了修正併發標記期間因用戶線程繼續運做而致使標記產生變更的那一部分對象的標記記錄,虛擬機將這段時間對象變化記錄在線程的 Remembered Set Logs 中,這個階段須要把 Remembered Set Logs 中的數據合併到 Remembered Set 裏,須要停頓線程,可是能夠並行執行。 最後的篩選回收階段會對 Region 的回收價值和成本進行排序,根據用戶所指望的 GC 停頓時間來制定回收計劃。

查看JVM所使用的收集器

java -XX:+PrintCommandLineFlags -version
複製代碼

在終端執行上述命令後,便可查看 JVM 所使用的收集器。

image

-XX:+UseParallelGC : 是虛擬機運行在 Server 模式下的默認值,打開此開關後,使用 Parallel Scavenge + Serial Old (PS MarkSweep) 的收集器組合進行內存回收。

參考

  • 《深刻理解Java虛擬機:JVM高級特性與最佳實踐 第二版》
相關文章
相關標籤/搜索