6.HotSpot中的GC收集器簡介

目錄

  • 概述
  • 新生代GC
  • 老年代GC
  • java789默認GC搭配
  • 垃圾收集器相關參數總結

概述

整理概括HotSpot中的GC收集器相關性能,算法使用,GC過程和相互搭配。須要先明確一個觀點:GC收集器根本上來講沒有絕對的優劣,咱們只能根據具體場景選擇最適合的GC組合,而不是選擇一個完美的GC組合。
介紹以前,先須要瞭解兩個名詞概念:java

  • 並行:多條GC線程並行工做,此時用戶線程仍處於停頓狀態
  • 併發:用戶線程與垃圾收集線程同時執行(並行或交替執行)

HotSpot虛擬機的垃圾收集器(JDK1.7).png

新生代GC

Serial收集器

  • 單線程
單線程有兩個方面含義: 一方面,serial收集器只使用一個CPU或一條收集線程進行GC; 另外一方面,serial進行GC時,須要暫停其餘全部的工做線程直到垃圾回收結束(Stop The World)
一方面,Serial收集器只是用一條GC線程去執行收集任務;另外一方面,Serial收集器進行收集時,必須暫停其餘全部的工做線程(Stop The World),直到收集結束。
  • 新生代採用複製算法;老年代採用標記-整理算法
  • Client模式下默認新生代收集器,能與CMS搭配使用

Serial/Serial Old收集器運行過程.png

ParNew收集器

  • 多線程GC,採用多線程進行收集工做
  • Server模式下的虛擬機中首選的新生代收集器,能與CMS搭配使用
  • 除多線程GC外,其他參數包括Serial收集器可用的全部控制參數、Stop The World、收集算法、對象分配規則、回收策略都與Serial徹底同樣

ParNew/Serial Old收集器運行過程.png

Parallel Scavenge收集器

  • 多線程並行GC
  • 新生代採用複製算法;老年代採用標記-清除算法
  • 關注吞吐量
  • GC自適應調節策略
吞吐量 = 運行用戶代碼時間 / (運行用戶代碼時間 + 垃圾收集時間)

CMS等收集器關注點是儘量縮短垃圾收集時用戶線程停頓的時間,Parallel Scavenge收集器關注的是達到一個可觀的吞吐量
停頓時間短適合須要和用戶交互多的程序;高吞吐量能夠高效利用CPU使用率,適合在後臺運算而不須要太多交互的任務算法

Parallel Scavenge收集器提供兩個參數用於控制吞吐量
-XX:MaxGCPauseMillis :最大垃圾收集停頓時間。值與新生代空間和吞吐量成反比。
-XX:GCTimeRatio:吞吐量大小。值能夠理解爲正常運行時間相對垃圾收集時間的倍數,即正常運行時間/垃圾回收時間,默認值爲99,即容許最大1%(1/1+99)的垃圾收集時間。多線程

GC自適應調節策略
Parallel Scavenge收集器還有一個參數-XX:+UseAdaptiveSizePolicy設置當前系統是否使用自適性系統參數調節,當開關打開時,系統不須要手動設置新生代大小、Eden和Survivor比例、晉升老年代對象年齡。併發

老年代GC

Serial Old收集器

  • Serial收集器老年代版本
  • 單線程
  • 標記-整理算法
  • JDK1.5 以及之前的版本中與 Parallel Scavenge 收集器搭配使用
  • CMS收集器備用預案,在CMS發生「Concurrent Mode Failure」時使用

Serial/Serial Old收集器運行過程.png

Parallel Old收集器

  • Parallel Scavenge收集器老年代版本,與Parallel Scavenge收集器搭配,構成「名副其實」的「吞吐量優先」收集器
  • 多線程並行GC
  • 標記-整理算法

![Parallel Scavenge/Parallel Old
收集器運行過程.png](https://upload-images.jianshu...佈局

CMS(Concurrent Mark Sweep)收集器

HotSpot第一款真正意義上的併發收集器。第一次實現了GC線程和工做線程(基本上)同時工做性能

收集過程

  • 初始標記
  • 併發標記
  • 重複標記
  • 併發清除

初始標記

只標記GC Roots能直接關聯到的對象,須要Stop The World(STW)。spa

併發標記

進行GC Roots引用鏈追蹤,標記全部有關聯的對象。這時GC線程能和用戶線程同時工做(用書上的形容是:真正的實現了你邊丟垃圾,你媽媽邊打掃衛生)。線程

重複標記

修正併發標記時,發生引用關係變化的那部分對象的引用,須要Stop The World。設計

併發清除

使用併發-清除算法對垃圾對象進行清除。3d

併發重置

CMS清除內部狀態,爲下次GC作準備

評價

  • 併發收集、低停頓

整個過程當中耗時最長的併發標記和併發清除過程收集器線程均可以與用戶線程一塊兒工做,因此,從整體上來講,CMS收集器的內存回收過程是與用戶線程一塊兒併發執行的

  • 併發-清除算法

不足

  • 與用戶線程爭奪CPU資源

雖然併發標記和併發清除時,不會致使用戶線程停頓,但因爲佔用一部分線程資源而致使應用程序速度變慢。CMS默認啓動的回收線程是(CPU數量 + 3) / 4

  • 沒法處理浮動垃圾

CMS收集器進行到併發清除階段時,因爲併發執行,系統仍然會產生一些垃圾,這些垃圾產生在標記以後,因此須要等待下次GC再清除他們,這些垃圾叫作「浮動垃圾」。正因如此,CMS收集器對老年代須要預留一部分空間提供併發收集時的程序運做使用。
CMS經過設置參數(-XX:CMSInitiatingOccupancyFraction)用來表示老年代使用多少空間時,激活CMS。設置這個參數須要有兩方面的考量:一方面,當參數值設置太低,觸發CMS的GC次數會變多,下降性能;另外一方面,當參數值設置太高,剩餘空間不足以存儲產生的浮動垃圾,系統會報「Concurrent Mode Failure」,系統將啓動預備方案:使用Serial Old收集器進行老年代的垃圾收集,這樣致使耗時更多,影響性能。

  • 併發-清除算法產生大量空間碎片

併發-清除算法將產生大量空間碎片,當大對象進入內存時,會因爲沒有足夠的連續內存空間分配而提早觸發Full GC。
爲此設計者提供了兩個參數。-XX:+UseCMSCompactAtFullCollection開關參數控制CMS收集器在須要進行Full GC時,是否開啓內存碎片整理過程(默認是開啓的)。-XX:CMSFullGCsBeforeCompaction設置執行多少次不壓縮內存空間的Full GC後,進行一次帶壓縮的Full GC(默認爲0,即每次進入Full GC都要進行碎片整理)。

CMS收集器運行過程.png

G1收集器(暫時根據《深刻理解Java虛擬機》第二版總結的,以後看了第三版再更新)

代替Parallel Scavenge和Parallel Old組合收集器,成爲JDK1.9服務端模式下默認垃圾收集器。設計初衷是創建起「停頓時間模型」的收集器,即支持指定在一個長度爲M毫秒的時間片斷內,消耗在GC上的時間不超過N毫秒這樣的目標。

簡述

  • 可預測的停頓
  • 分代收集
  • 併發
  • 標記-清除,兩個Region之間局部表現爲標記-複製
  • Region不分代致使記憶集和其餘內存消耗較大。
可預測的停頓:G1支持使用者設置在M時間中停頓N秒。G1在後臺維護一個列表用於記錄每一個Region裏面的垃圾回收的價值(回收得到的空間大小和回收所需時間),根據用戶設置的時間,制定回收計劃,優先回收價值大的區域(Garbage-First的由來)。

收集思想(Mixed GC模式)

以前的垃圾收集器的垃圾收集對象爲整個新生代(Minor GC)、整個老年代(Major GC)或整個Java堆(Full GC)。而G1面向堆內存的任何部分來組成回收集進行垃圾回收,衡量標準再也不是內存屬於哪一個年代,而是哪塊內存中存放的垃圾數量最多,回收收益最大

堆內存佈局(Region、Humongous)

爲了實現這一收集目標,G1的堆內存佈局開創了基於Region的堆內存佈局。
G1雖仍然遵循分代收集,可是不一樣於以前的收集器將年輕代、年老代和元空間按照固定大小以及固定數量進行區域劃分,而是將連續的Java堆劃分爲大小相等的若干區域——Region,每一個區域根據須要能夠是任何年代的對象,各個年代沒有物理連續只有邏輯上的連續。收集器就能夠根據扮演不一樣年代的Region採用不一樣的回收策略。
除此以外,增長了一個區域——Humongous區域,用於存儲巨型對象,若是一個對象佔用空間超過Region容量的通常,G1則認爲這是一個巨型對象(Region取值範圍爲1MB~32MB,應爲2的N次冪,經過-XX:G1HeapRegionSize設定)。若是一個Region裝不下一個巨型對象,則會尋找連續的Humongous分區來存儲,有時爲找到連續的H分區,有時會觸發Full GC。H區域的出現避免了短時間存在的巨型對象對GC形成負面影響。G1大多數行爲把H區域當作老年代看待。
G1分區示例.png

可預測的停頓時間模型

有了新的垃圾收集思想和堆內存佈局,「可預測的停頓時間模型」得以實現:

  • 追求應付應用的內存分配速率而不是追求一次把Java堆收集乾淨
  • 每次收集時將Region做爲回收最小單元,即每次回收的內存空間都是Region的整數倍,避免了全區域收集,所以時間可控
  • 收集具體思路是讓G1收集器去跟蹤各個Region裏面的垃圾堆積的「價值」大小,即回收獲得的空間以及回收所需時間的經驗值,而後在後臺維護一個優先級列表,每次根據用戶設定的收集停頓時間(默認200毫秒)優先處理回收價值收益最大的那些Region

收集過程

  • 初始標記
  • 併發標記
  • 最終標記
  • 篩選回收

初始標記

只標記GC Roots能直接關聯到的對象,修改TAMS指針值,讓下個階段能正確的在可用Region中分配對象。須要停頓線程,但借用Minor GC的時候同步完成,沒有額外停頓。

併發標記

從GC Roots進行可達性遍歷,對整個Java堆的對象圖進行掃描,找出回收對象。這個階段能夠和用戶線程併發執行。還要從新處理SATB記錄下的在併發時引用有變更的對象。

最終標記

處理併發階段後遺留下來的少許的SATB 記錄,須要短暫暫停。

SATB(Snapshot At The Beginning):簡單地說就是初始標記階段和併發標記階段標記爲活的的對象就是活的。而後併發標記階段新增或者引用從新執行的對象也認爲是活的。其餘的就是死的

篩選回收

更新Region統計數據,對各Region回收價值和成本進行排序,根據用戶指望停頓時間來指定回收計劃。回收過程將決定回收的那一部分Region的存活對象複製到空的Region中,而後清理掉舊的Region的所有空間。須要停頓用戶線程。

由回收過程能夠看出G1並不是純粹追求低延遲,而是在延遲可控的狀況下得到儘量高的吞吐量。

G1收集器運行過程.png

java789默認GC搭配

jdk1.7 Parallel Scavenge(新生代)+Parallel Old(老年代)
jdk1.8 Parallel Scavenge(新生代)+Parallel Old(老年代)
jdk1.9 G1

垃圾收集器參數總結

垃圾收集器參數總結1.png
垃圾收集器參數總結2.png

相關文章
相關標籤/搜索