面試官,不要再問我「Java 垃圾收集器」了

若是Java虛擬機中標記清除算法、標記整理算法、複製算法、分代算法這些屬於GC收集算法中的方法論,那麼「GC收集器」則是這些方法論的具體實現。java

在面試過程當中這個深度的問題涉及的比較少,但對於理解上面的這些算法有很好的幫助。若是可以如數家珍,也是面試中的加分項,仍是那句話,畢竟面試官的時間也很少了。面試

概念準備

在學習Java GC收集器以前,須要先了解一些內容和概念,首先若是沒有學習《面試官,不要再問我「Java GC垃圾回收機制」了》的可先學習該篇文章,瞭解基本算法方法論。算法

下面瞭解幾個概念以幫助後面的學習:線程暫停(Stop The World)、安全點(Safepoint)、安全區(Safe region)。安全

在執行可達性分析的時候會出如今分析的過程當中對象關係引用等發生了變化,爲了保證分析的準確性,就必須在分析的過程當中暫停全部Java線程,Sun將這一事件稱做「Stop The World」。微信

那麼,何時暫停合適呢?並非全部的時刻均可以暫停全部線程進行GC的,只有到達某些點才能夠進行GC操做,這些點就稱做安全點(Safepoint)。多線程

安全點的設置不能太少,那樣GC等待的時間就會太長,但也不能太多不然會增長運行時的負擔。併發

因此,安全點的選定基本上是以程序「是否具備讓程序長時間執行的特徵」爲標準進行選定的。好比,循環的末尾、方法臨返回前/調用方法的call指令後、可能拋異常的位置等。jvm

HotSpot採用主動中斷的方式,讓執行線程在運行期輪詢是否須要暫停的(GC設置的)標誌,若須要則中斷掛起。佈局

對於正在運行的線程,能夠主動運行到安全點並暫停執行,可是對於那些正在Sleep或阻塞的線程,當它們從新執行時可能已通過了安全點,但此時GC可能還沒完成垃圾回收,這種狀況該怎麼辦呢?學習

因而就有了安全區(Safe region)的概念,安全區是一塊區域,在該區域中引用都不會被修改。好比,線程進入到安全區的時候先標識本身進入了安全區,等它被喚醒準備離開時,先檢查GC是否完成,若是完成則能夠離開,不然就在安全區等待。

瞭解了上面的基本概念以後,下面正式進入垃圾收集器的講解。

垃圾收集器分類

先經過下圖瞭解一下Hotspot的8種垃圾收集器及其應用。image

兩個收集器之間的連線,表示它們能夠搭配使用。收集器所處的區域表示它是屬於新生代收集器仍是老年代收集器。其中ZGC爲Java11引入的新的垃圾收集器。

默認垃圾收集器

不一樣Java版本採用的默認收集器以下。

image

Serial收集器

Serial收集器是最基本、發展歷史最悠久的收集器,是一個單線程的收集器。在進行垃圾收集時,必須暫停其餘全部的工做線程,直到它收集結束。就是所謂的「Stop The World。」

image

ParNew收集器

ParNew收集器其實就是Serial收集器的多線程版本。除了使用多線程進行垃圾收集外,其他行爲包括Serial收集器可用的全部控制參數、收集算法(複製算法)、Stop The World、對象分配規則、回收策略等與Serial收集器徹底相同,二者共用了至關多的代碼。

image

Parallel Scavenge收集器

Parallel Scavenge收集器是一個新生代蒐集器,主要採用複製算法,與ParNew相似。但關注點與其餘蒐集器不一樣,目標是達到一個可控的吞吐量。

Serial Old收集器

Serial Old是Serial收集器的老年代版本,一樣是一個單線程收集器,使用標記-整理算法。運做圖同Serial蒐集器。

Parallel Old收集器

Parallel Old是Parallel Scavenge收集器的老年代版本,使用多線程和「標記-整理」算法。在JDK 1.6中才開始提供。

image

CMS收集器

CMS(Concurrent Mark and Sweep 併發-標記-清除),是一種以獲取最短回收停頓時間爲目標的收集器。基於併發、使用標記清除算法,只針對老年代進行垃圾回收。

CMS收集器工做時,儘量讓GC線程和用戶線程併發執行,以達到下降STW時間的目的。

整個操做步驟分爲四步:初始標記(CMS initial mark)、併發標記(CMS concurrent mark)、從新標記(CMS remark)、併發清除(CMS concurrent sweep)。

image

在上圖過程當中,初始標記和從新標記都會觸發「Stop The World」。

初始標記僅僅只是標記一下GC Roots能直接關聯到的對象,速度很快,在Java7中是單線程,在Java8之後可採用多線程。

發標記階段GC線程和應用線程併發執行,初始標記出來的存活對象,而後繼續遞歸標記這些對象可達的對象。

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

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

缺點:對CPU資源很是敏感、沒法處理浮動垃圾、標記-清除算法致使的空間碎片。

G1收集器

G1(Garbage-First)是一款面向服務端應用的垃圾收集器。支持新生代和老年代空間的垃圾收集。

該收集器可充分利用CPU和硬件縮短STW的時間,還具備「整合空間」、「可預測停頓」等特色。好比,可創建可預測的停頓時間模型,能讓使用者明確指定在一個長度爲N毫秒的時間片斷內,消耗在垃圾收集上的時間不得超過N毫秒。

使用G1收集器時,Java堆的內存佈局與其餘收集器有很大差異,它將整個Java堆劃分爲多個大小相等的獨立區域(Region),雖然還保留有新生代和老年代的概念,但新生代和老年代再也不是物理隔閡了,它們都是一部分(能夠不連續)Region的集合。

image

G1會跟蹤各個Region裏面的垃圾堆積的價值大小(回收所得到的空間大小以及回收所需時間的經驗值),在後臺維護一個優先列表,每次根據容許的收集時間,優先回收價值最大的Region(這也就是Garbage-First名稱的來由)。

G1收集器的運做大體可劃分爲如下幾個步驟:初始標記(Initial Marking)、併發標記(Concurrent Marking)、最終標記(Final Marking)、篩選回收(Live Data Counting and Evacuation)。

整個流程來看,前幾個步驟與CMS的流程很類似。一樣的在初始標記和最終標記的過程當中都會觸發「Stop The World」。

image

其中,篩選回收階段其實也能夠作到與用戶程序一塊兒併發執行,可是由於只回收一部分Region,時間是用戶可控制的,並且停頓用戶線程將大幅度提升收集效率。

ZGC收集器

ZGC(Z Garbage Collector),是一款可伸縮、低延遲、併發垃圾回收器。在Java11中引入,應用Linux64位系統。

其旨在實現如下幾個目標:停頓時間不超過10ms、停頓時間不隨heap大小或存活對象大小增大而增大、能夠處理從幾百兆到幾T的內存大小。

ZGC將內存劃分爲多個區域,也稱爲ZPage。ZPages能夠動態建立和銷燬。它們也能夠動態調整大小(與G1 GC不一樣),是2 MB的倍數。如下是堆區域的大小組:Small (2 MB)、Medium (32 MB)、Large (N * 2 MB)。

ZGC堆能夠屢次出現這些堆區域。中型和大型區域是連續分配的,以下圖所示:

image

與其餘GC不一樣,ZGC的物理堆區域能夠映射到更大的堆地址空間(其中能夠包括虛擬內存)。

image

ZGC的執行過程包括:標記(初始標記、併發標記、邊緣狀況處理)、從新定位(查找從新定位塊、根引用從新定位並更新、併發定位其餘對象並存儲新舊地址映射)、從新映射。

其中標記中的初始標記和邊緣狀況處理會引起「Stop The World」,從新定位中的「根引用從新定位並更新」也會引起「Stop The World」。

其中從新映射流程圖以下:

image

ZGC打算以較短的應用程序暫停時間來支持大堆大小。爲了實現此目標,它使用了包括彩色64位指針,負載屏障,重定位和從新映射的技術。

小結

本文介紹了場景的垃圾收集器以及相關的概念,屬於較深層次的內容,針對這些內容還能夠進一步進行橫向或縱向拓展。

有朋友在評論區問,學這些有底層什麼用?固然咱們不只僅是爲了面試,就拿關於JVM結構及Java8 JVM內存結構變更來講吧。

昨天在部署一個比較大的項目時就出現「java.lang.OutOfMemoryError: Metaspace」異常,若是學習了以前的相關內容能夠很輕易的定位到是由於JVM設置了Metaspace的上限參數,而且參數值設置小致使的。

最後,《面試官系列》正在持續更新,歡迎關注公衆號「程序新視界」,得到最新內容。

原文連接:《面試官,不要再問我「Java 垃圾收集器」了

《面試官》系列文章:


程序新視界:精彩和成長都不容錯過

程序新視界-微信公衆號

相關文章
相關標籤/搜索