1. 程式人生 > >java虛擬機學習(五)--垃圾收集器總結

java虛擬機學習(五)--垃圾收集器總結

9.png 階段 大對象 技術 增加 系統 current 提前 及其

JVM——垃圾收集器總結

一、垃圾收集器概覽  

收集算法是內存回收的方法論,垃圾收集據是內存回收的具體實現。Java虛擬機規範中對垃圾收集器應該如何實現沒有規定,不同的廠商、不同版本的虛擬機所提供的垃圾收集器可能會有很大差別,一般都會提供參數供用戶根據自己的所用特點和要求組合出各個年代所使用的收集器。下面是基於JDK 1.7 Update 14 之後的HotSpot 虛擬機垃圾收集器。如果兩個收集器之間有連線就說明它們可以搭配使用。直到現在還沒有最好的收集器,更加設有萬能的收集器,只是對具體應用選擇最合適的收集器。

垃圾收集器概覽圖如下:

技術分享圖片

1.1、Serial 收集器

  Serial 收集器是最基本、歷史最悠久的收集器,它是一個單線程的收集器,即它只會使用一個CPU 或一條收集線程去完成垃圾收集工作,而且在進行垃圾收集時, 必須暫停其他所有的工作錢程,直到它收集結束,雖然它有很大缺點,但依然是虛擬機運行在Client 模式下的默認新生代收集器。它也有著優於其他收集器的地方: 簡單而高效

。Serial 收集器沒有線程交互的開銷, 專心做垃圾收集,可以獲得很高的單線程收集效率。

  運行示意圖如下:

  技術分享圖片

·

1.2 ParNew 收集器  

ParNew 收集器其實就是Serial收集器的多線程版本,除了使用多條線程進行垃圾收集之外,其余行為包括Serial 收集器可用的所有控制參數、、收集算法、應用停機(Stop The World)、對象分配規則、回收策略等都與Serial 收集器完全一樣。ParNew是許多運行在Server 模式下的虛擬機中首選的新生代收集器。目前只有它能與CMS 收集器配合工作。ParNew 收集器在單CPU 的環境中不會有比Serial 收集器效果好。隨著使用的CPU 的數量的增加,它對於GC 時系統資源的利用提高。

垃圾收集的上下文語境中:

    • 並行(Parallel:指多條垃圾收集線程並行工作,但此時用戶線程仍然處於等待狀態。
    • 並發(Concurrent:指用戶線程與垃圾收集線程同時執行(但不一定是並行的,可能會交替執行),用戶程序繼續運行,垃圾收集程序運行在另一個CPU 上。

  技術分享圖片

1.3 Parallel Scavenge 收集器  

Parallel Scavenge 收集器是一個新生代收集器,使用復制算法,是並行的多線程收集器。Parallel Scavenge 收集器的目標則是達到一個可控制的吞吐量。吞吐量就是CPU 用於運行用戶代碼的時間與CPU 總消耗時間的比值,即 吞吐量=運行用戶代碼時間/( 運行用戶代碼時間+垃圾收集時間)

高吞吐量可以最高效率地利用CPU 時間,盡快地完成程序的運算任務,主要適合在後臺運算而不需要太多交互的任務。Parallel Scavenge 收集器也經常稱為“吞吐量優先”收集器

1.4 Serial Old 收集器 

Serial Old 是Serial 收集器的老年代版本, 也是一個單線程收集器,使用“標記一整理”算法。主要被Client 模式下的虛擬機使用。如果在Server 模式下,有兩大用途: 一個是在JDK 5 以及之前的版本中與Parallel Scavenge 收集器搭配使用。另一個就是作為CMS 收集器的後備預案,在並發收集發生Concurrent Mode Failure 的時候使用。

運行示意圖如下:

技術分享圖片

1.5 Parallel Old 收集器  

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

運行示意圖如下:

技術分享圖片

1.6 CMS 收集器

  CMS( Concurrent Mark Sweep ) 收集器是一種以獲取最短回收停頓時間為目標的收集器。停頓時間越短就越適合需要與用戶交互的程序,良好的響應速度能提升用戶體驗。目前很大一部分的Java 應用都集中在互聯網站或B/S 系統的服務端上,這類應用尤其重視服務的響應速度,希望系統停頓時間最短,以給用戶帶來較好的體驗。CMS 收集器就非常符合這類應用的需求。

  CMS 收集器是基於“標記一清除”算法實現的,整個過程分為4 個步驟:

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

  2. 並發標記(CMS concurrent mark)並發標記階段就是進行GCRoots Tracing 的過程

  3. 重新標記(CMS remark) : 需要“Stop The World ”。為了修正並發標記期間,因用戶程序繼續運作而導致標記產生變動的那一部分對象的標記記錄,這個階段的停頓時間一般會比初始標記階段稍長一些,但遠比並發標記的時間短

  4. 並發清除(CMS concurrent sweep)進行垃圾清理工作。

  運行示意圖如下:

   技術分享圖片

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

缺點:

CMS 收集器對CPU 資源非常敏感。在並發階段,它雖然不會導致用戶線程停頓,但是會因為占用了一部分線程(或者說CPU 資源)而導致應用程序變慢,總吞吐量會降低。CMS 默認啟動的回收線程數是(CPU 數量+3)/ 4。

CMS 收集器無法處理浮動垃圾( Floating Garbage ),可能出現“Concurrent Mode Failure”,失敗而導致另一次Full GC 的產生。CMS 並發清理階段用戶線程還在運行著,伴隨程序的運行會有新的垃圾產生,這一部分垃圾出現在重新標記過程之後, CMS 無法在本次收集中處理它們,只只留待下一次GC 時再將其清理掉。這一部分垃圾就稱為“浮動垃圾”。由於在垃圾收集階段用戶線程還需要運行,就要預留足夠的內存空間給用戶線程使用,因此CMS 收集器不能像其他收集器那樣等到老年代幾乎完全被填滿了再進行收集,CMS 收集器需要預留一部分空間提供並發收集時的程序運作使用。要是CMS 運行期間預留的內存無償滿足程序需要,就會出現一次“Concurrent Mode Failure 失敗,這時虛擬機將啟動後備預案:臨時啟用Serial Old 收集器來重新進行老年代的垃圾收集,會停頓較長時間。

收集結束時會產生大量空間碎片。CMS 基於“標記一清除”算法實現。多次垃圾收集後,空間碎片過多,給大對象分配帶來很大的麻煩,往往會出現老年代還有很大的空間剩余,但是無法找到足夠大的連續空間來分配當前對象,不得不提前觸發一次Full GC 。為了解決這個問題, CMS 收集器提供了-XX:+UseCMSCompactAtFullCollection 這個參數,用於在CMS收集器要進行FullGC時開啟內存碎片整理。默認值為0,表示每次進入FullGC 時都進行碎片整理。

1.7 G1 收集器

  收集器技術發展的最新成果,是面向服務端應用的垃圾回收器。它有下面的特點: 

  • 並發與並行:能利用多CPU、多核環境下優勢,使用多個CPU (CPU或者CPU 核心)來縮短Stop The World的停頓時間。部分其他收集器原本需要停頓Java 線程執行的GC動作, G1 收集器仍然可以通過並友的方式讓Java 程序繼續執行

  • 分代收集:G1中依然使用分代概念。G1可以不需要其他收集器配合就能獨立管理整個GC 堆,還能夠用不同的方式去處理新創建的對象和已經存在一段時間、經過多次GC 依舊存在的對象,進而獲得更好的收集效果.

  • 空間整合:GI從整體來看是基於“標記一整理”算法, 從局部(兩個Region 之間)後是基於“復制”算法實現的,這意味著GI1運行期間不會產生內存空間碎片,收集後能提供規整的可用內存. 這種特性有利於程序長時間運行,分配大的對象不會因為無法找到連續內存空間而提前觸發下一次GC。

  • 可預測的停頓:GI 除了低停頓外,還能建立預測的停頓時間的模型,能讓使用者明確指定在一個長度為M 毫秒的時間片段內,垃圾收的時間不得超過N 毫秒。

使用GI 收集器時,Java 堆的內存布局就與其他收集器有很大差別,它將整個Java 堆劃分為多個大小相等的獨立區域(Region),雖然保留有新生代和老年代的概念,但新生代和老年代不再是物理隔離,它們都是一部分Region(不需要連續)的集合。

G1收集器能建立預測的停頓時間模型,是因為它可以有計劃地避免在整個Java 堆中進行全區域的垃圾收集。G1跟蹤各個Region 裏每個垃圾堆積的價值大小(回收所獲得的空間大小以及回收所需時間的經驗值),在後臺維護一個優先隊列,根據允許的收集時間,優先回收價值最大的Region (這也就是Garbage-First 名稱的來由)。這種使用Region 劃分內存空間以及有優先級的區域回收方式,保證了G1收集器在有限的時間內可以獲取盡可能高的收集效率。

在GI 收集器中, Region 之間的對象引用以及其他收集器中的新生代與老年代之間的對象引用, 虛擬機都是使用Remembered Set 來避免全堆掃描。

不計算維護Remembered Set 的操作, GI收集器的運作可劃分為以下四個步驟:

  1. 初始標記(Initial Marking):僅標記GC Roots能直接關聯到的對象並且修改TAMS(Next to Top at Mark Start)的值。讓下一階段用戶程序並發運行時,能在正確可用的Region中創建新對象,這個階段要停頓線程,但耗時短。

  2. 並發標記(Concurrent Marking):從GC Roots開始對堆中對象進行可達性分析,找出存活對象,這個階段耗時少,可以與用戶程序並發執行。

  3. 最終標記(Final Marking):為了修正並發標記期間,因用戶程序繼續運作而導致標記產生變動的那一部分對象的標記記錄,虛擬機將這段時間變化記錄在線程Remembered Set中,這個階段可以並行執行。

  4. 篩選回收(Live Data Counting and Evacuation):對各個Region的回收價值和成本進行排序,根據用戶所期望的GC停頓時間來制定回收計劃,可以與用戶程序並發執行。

  運行示意圖如下:

  技術分享圖片

java虛擬機學習(五)--垃圾收集器總結