從原始到最新的垃圾回收器

前言


個人全部文章同步更新與Github--Java-Notes,想了解JVM,HashMap源碼分析,spring相關,劍指offer題解(Java版),能夠點個star。能夠看個人github主頁,天天都在更新喲。git

邀請您跟我一同完成 repogithub


閱讀本篇文章,你首先的知道這兩個概念算法

  • 三種垃圾回收算法
  • 怎麼判斷對象「已」️死

若是不瞭解垃圾回收算法或者是斷定對象存活的可達性分析算法,能夠參看個人這篇博文,垃圾回收spring

垃圾回收器是垃圾回收的具體實現,這裏只講Hotspot虛擬機的7中不一樣的垃圾回收器。安全

  • 新生代
    • Serial
    • ParNew
    • Parallel Scavenge
  • 老年代
    • CMS
    • Serial Old
    • Parallel old
  • 兩者皆可的 G1(JDK1.9以後,成爲默認的收集器)
  • ZGC(文章中會提到)

虛擬機使用的時候是採用組合的方式,可是也不是能夠隨意組合的,組合方式以下多線程

Serial

特色

  • 單線程
  • Stop The world
  • 在client模式下默認的新生代的收集器

從名字能夠看出來他是一個單線程的收集器(Serial有串行的意思),他在工做的時候,用戶的其餘全部工做線程都必須中止。這也是"Stop the World"的由來。併發

可是這種的工做方式讓人聽難受的,你想一想你工做的時候正在興頭上,立刻高潮了,忽然戛然而止。GC線程出來工做了,你一動不能動。由於它自動發起的,自動完成的,用戶不可見,不可預知。源碼分析

下面用圖給你解釋下。(Serial搭配Serial Old)性能

若是不瞭解標記複製算法或者安全點能夠查看個人這篇博文--垃圾回收算法網站

ParNew

特色

  • 多線程版 Serial收集器

  • 不少server模式下首選的新生代收集器

  • 其餘和Serial同樣

多線程版不必定意味着比單線程的Serial的效率高,由於他有別的線程的頻繁交互,隨着CPU的增多,纔會比他的效率高

Parallel Scanvenge

特色

  • 吞吐量優先(最大的特點)

  • 自動調節適應

  • 多線程

你能夠把收集過程和ParNew差很少,圖片也差很少。可是他有兩個特點

吞吐量優先

其餘收集器關注的是減小垃圾收集時用戶停頓的時間。而他關注的是達到一個可控的吞吐量

吞吐量是CPU運行用戶代碼的時間與CPU消耗的總時間的比值

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

虛擬機總共運行了 100s,垃圾回收用了 1s,那吞吐量就爲99%

由兩個參數控制

  • -XX: MaxGCPauseMillis
  • -XX: GCTimeRatio

根據名字就能夠看出來啊,第一個是說回收時的暫停時間、單位毫秒,第二個是回收時間所佔的比例。

可是第一個設置的越小,垃圾回收越頻繁,總時間不必定會降低。應該很好理解

第二個是GC時間比例,至關於吞吐量的倒數。範圍(1,100)的整數。若是設置爲1,值爲50%=1/(1+1)。默認爲99,即容許回收時間佔1% = 1/(1+99).

自動調節適應

參數:-XX:UseAdaptiveSizePolicy

若是打開,那麼你就能夠不用本身手工去指定新生代的大小、Eden和Survivor區的比例、晉升老年代對象大小(若是一個對象足夠大,那麼能夠直接在老年代分配)。

若是對於收集器的運做不太瞭解,那麼能夠打開這個參數,交給虛擬機本身完成

Serial Old

特色

  • 和新生代的Serial同樣
  • 標記整理算法

圖片參考 Serial

Parallel Old

特色

  • 標記-整理算法
  • 吞吐量優先

這個收集器是在JDK1.6以後才提供,沒有提供以前 新生代的Parallel Scavenge的地位比較尷尬。還記得我一開始的圖嗎,若是沒有這個收集器,新生代的 Parallel 只能選擇 Serial,他和 CMS 不兼容。可是Serial Old 這個收集器在多線程模式下,以及老年代很大的狀況下的性能算是表現比較差的。通常選擇組合都去用 PerNew + CMS了,他就很尷尬。

到了JDK1.6以後,在注重吞吐量以及CPU資源敏感的場合,能夠優先考慮Parallel組合了,這個時候 Serial Old ,在server模式下就做爲CMS的後備方案,在併發收集時發生 Concurrent Mode Failure 的時候使用(介紹CMS的時候我會說明)

圖片描述以下圖所示

CMS

CMS(Concurrent Mark Sweep)是一款以獲取最短回收停頓時間爲目標的收集器。很是符合在很大一部分的Java應用集中在互聯網站或者B/S系統的服務端上應用的需求。由於這種的應用尤爲重視服務的響應速度,但願停頓時間短,以此帶來更好的用戶體驗

特色

  • 標記-清除(其餘老年代的都是標記整理)
  • 併發收集
  • 以獲取最短回收停頓時間爲目標

回收步驟

  • 初始標記
  • 併發標記
  • 從新標記
  • 併發清除

記住:其中 初始標記從新標記須要"Stop The World",不過期間很短

初始標記的過程僅僅標記GC Root直接關聯的對象,他並不去標記間接關聯的。這個過程交給第二階段併發標記來完成;

從新標記階段則是爲了修正併發標記期間因用戶程序繼續運做而致使標記產生變更的那一部分對象的標記記錄,停頓時間比第一階段的初始標記稍長。

第四個階段,併發清除。也是能夠併發完成的。

由於在這裏第一次出現併發的概念,我解釋一下在垃圾回收的時候併發和並行的概念。注意只是垃圾回收中的並行併發。

並行是,多個回收線程工做,工做線程不工做。

併發是,回收線程和工做線程一塊兒工做。

因此你能夠說 ParNew 是並行的收集器,但不能說是併發的收集器

收集器工做圖解以下圖所示

缺點

  • 對CPU資源敏感
  • 沒法處理浮動垃圾
  • 標記-清除算法

若是CPU資源不多,可開啓線程也不多。那麼CMS會讓用戶體驗很是差,由於要分出至關多的資源去運行垃圾回收,致使運行程序的資源變少。

由於他是併發進行回收的,因此當我在收集時,你還在產生垃圾,那麼這部分垃圾被稱爲的浮動垃圾。而這部分垃圾不得不在我下一次回收時才能回收。並且他也不能充分利用空間,畢竟要分一部分給浮動垃圾,因此若是垃圾過多,空間不能知足,就會出現"Concurrent Mode Failure"提早觸發一次 Full GC,這個過程會啓動 Serial Old進行收集。

G1

G1(Garbage First)是一款面向服務端應用的垃圾收集器。在JDK1.9被設置成默認的垃圾回收器,基本算是最前沿的垃圾回收器。固然還有更牛逼的垃圾回收器ZGC。不過他是在JDK 11 才被推出,因此通常人用不到,也不用瞭解,想了解能夠看下這篇文章,JDK11的ZGC

特色

  • 並行併發
  • 分代收集
  • 空間整合(算是最大的不一樣)
  • 可預測的停頓
  • 自己並不提供Full GC

咱們先看傳統的年代分割

(JDK1.8以後已經移除了永久代,改成元空間了)

下面是G1的分割

經過圖片能夠看出來,以前的垃圾回收器的年代是空間(邏輯上)連續的,而G1的空間是不連續的,他被劃分爲一個個大小相等的 region

**從總體上看,他是採用"標記-整理算法",局部(兩個region之間)看是"標記-複製算法"。**因此G1運做期間不會產生內存碎片。

可預測的停頓:是指用戶能夠指定整個GC過程的指望停頓時間,經過參數-XX:MaxGCPauseMillis,那麼他是怎麼知足用戶指望的時間呢?就須要停頓預測模型了。G1根據這個模型統計計算出來的歷史數據來預測本次收集須要選擇的Region數量,從而儘可能知足用戶設定的目標停頓時間

收集過程

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

先用一張圖解釋一下步驟

從圖中咱們能夠看到,G1的過程和CMS差很少,可是仍是有一些區別,主要是最後的清理階段,他也是STW(Stop The World)的。其餘更多的是算法的差異。

相關文章
相關標籤/搜索