詳細介紹Java虛擬機器器:JVM垃圾回收器

2022-07-14 18:01:48
本篇文章給大家帶來了關於的相關知識,其中主要整理了JVM垃圾回收器的相關問題,包括了Serial與Serial Old 回收器、ParNew 回收器、Parallel 與Parallel Old 回收器等等內容,下面一起來看一下,希望對大家有幫助。

推薦學習:《》

並行與並行

  • 並行(Parallel):並行描述的是多條垃圾收集器執行緒之間的關係,說明同一時間有多條這樣的執行緒在協同工作,通常預設此時使用者執行緒是處於等待狀態。
  • 並行(Concurrent):並行描述的是垃圾收集器執行緒與使用者執行緒之間的關係,說明同一時間垃圾收集器執行緒與使用者執行緒都在執行。由於使用者執行緒並未被凍結,所以程式仍然能響應服務請求,但由於 垃圾收集器執行緒佔用了一部分系統資源,此時應用程式的處理的吞吐量將受到一定影響。

垃圾回收器的分類

1. 按執行緒數分
按照執行緒數(用於垃圾回收的)可以分為序列垃圾回收器並行垃圾回收器

  • 序列垃圾回收器:在同一時間段內只允許有一個cPU用於執行垃圾回收操作,此時工作執行緒被暫停,直至垃圾收集工作結束。
  • 並行垃圾回收器:可以運用多個CPU同時執行垃圾回收。
    在這裡插入圖片描述
    2. 按工作模式分
    按照按工作模式可以分為並行式垃圾回收器獨佔式垃圾回收器
  • 並行式垃圾回收器:在同一時間段內只允許有一個cPU用於執行垃圾回收操作,此時工作執行緒被暫停,直至垃圾收集工作結束。
  • 獨佔式垃圾回收器:可以運用多個CPU同時執行垃圾回收。

在這裡插入圖片描述
3. 按碎片處理方式分
按照按工作模式可以分為壓縮式垃圾回收器非壓縮式垃圾回收器

壓縮式垃圾回收器會在回收完成後,對存活物件進行壓縮整理,消除回收後的碎片。

7種經典的垃圾回收器

  • 序列回收器: serialserial old
  • 並行回收器: ParNewParallel scavengeParallel old
  • 並行回收器: CMSG1

在這裡插入圖片描述

  • 新生代收集器: serial、ParNew、Parallel scavenge;
  • 老年代收集器: Serial old、Parallel old、CMS;
  • 整堆收集器: G1;

垃圾回收器

Serial與Serial Old 回收器

Serial收集器是最基礎、歷史最悠久的收集器,曾經(在JDK 1.3.1之前)是HotSpot虛擬機器器新生代收集器的唯一選擇。Serial收集器是一個單執行緒工作的收集器,在它進行垃圾收集時,必須暫停其他所有工作執行緒,直到它收集結束。
Serial Old是Serial收集器的老年代版本。

  • Serial回收器採用複製演演算法、序列回收和「Stop The World」 機制執行垃圾回收。
  • Serial Old回收器標記—壓縮演演算法、序列回收和「Stop The World」 機制執行垃圾回收。

在這裡插入圖片描述

ParNew 回收器

ParNew收集器實質上是Serial收集器的多執行緒並行版本,除了同時使用多條執行緒進行垃圾收集之 外,其餘的行為包括Serial收集器可用的所有控制引數、收集演演算法、Stop The World、物件分配規則、回收策略等都與Serial收集器完全一致。
在這裡插入圖片描述

Parallel 與Parallel Old 回收器

Parallel Scavenge收集器也是一款新生代收集器,它同樣是基於標記-複製演演算法實現的收集器,也是 能夠並行收集的多執行緒收集器。
和ParNew收集器不同,Parallel scavenge收集器的目標則是達到一個可控制的吞吐量,它也被稱為吞吐量優先的垃圾收集器。

吞吐量:處理器用於執行使用者程式碼的時間與處理器總消耗時間的比值。

高吞吐量可以最高效率地利用處理器資源,儘快完成程式的運算 任務,主要適合在後臺運算而不需要太多互動的分析任務。

Parallel Old是Parallel Scavenge收集器的老年代版本,支援多執行緒並行收集,基於標記-整理演演算法實 現。

在這裡插入圖片描述

CMS回收器

CMS(Concurrent Mark Sweep)收集器是一種以獲取最短回收停頓時間為目標的收集器。

CMS收集器是基於標記-清除演演算法實現的,它的運作可以分為四個步驟,包括:

  1. 初始標記
    初始標記僅僅只是標記一下GC Roots能直接關聯到的物件,速度很快;
  2. 並行標記
    並行標記階段就是從GC Roots的直接關聯物件開始遍歷整個對 象圖的過程,這個過程耗時較長但是不需要停頓使用者執行緒,可以與垃圾收集執行緒一起並行執行;
  3. 重新標記
    重 新標記階段則是為了修正並行標記期間,因使用者程式繼續運作而導致標記產生變動的那一部分物件的 標記記錄,這個階段的停頓時間通常會比初始標記階段稍長一 些,但也遠比並行標記階段的時間短;
  4. 並行清除
    清理刪除掉標記階段判斷的已經死亡的 物件,由於不需要移動存活物件,所以這個階段也是可以與使用者執行緒同時並行的。

在這裡插入圖片描述
CMS收集器無法處理「浮動垃圾」,有可能出現「Con-current Mode Failure」失敗進而導致另一次完全「Stop The World」的Full GC的產生。
在CMS的並行標記和並行清理階段,使用者執行緒是還在繼續執行的,程式在執行自然就還會伴隨有新的垃圾物件不斷產生,但這一部分 垃圾物件是出現在標記過程結束以後,CMS無法在當次收集中處理掉它們,只好留待下一次垃圾收集 時再清理掉。這一部分垃圾就稱為「浮動垃圾」。

同樣也是由於在垃圾收集階段使用者執行緒還需要持續執行,那就還需要預留足夠記憶體空間提供給使用者執行緒使用,因此CMS收集器不能像其他收集器那樣等待 到老年代幾乎完全被填滿了再進行收集,必須預留一部分空間供並行收集時的程式運作使用。

CMS是基於「標記-清除」演演算法實現的收集器,意味著收集結束時會有大量空間碎片產生,空間碎片過多時,將會給大物件分配帶來很大麻煩。

為什麼不使用標記—壓縮演演算法避免碎片?

因為當並行清除時,用標記—壓縮整理記憶體的話,原來的使用者執行緒使用的記憶體就無法使用。要保證使用者執行緒繼續執行,前提是它執行的資源不受影響。標記—壓縮更適合「Stop The World」場景下使用。

G1(Garbage First)回收器

Garbage First開創了收集 器面向區域性收集的設計思路和基於Region的記憶體佈局形式,它是一款主要面向伺服器端應用的垃圾收集器,主要針對配備多核CPU及大容量記憶體的機器,以極高概率滿足GC停頓時間的同時,還兼具高吞吐量的效能特徵。

G1收集器出現之前的所有其他收集器,垃圾收集的目標範圍要麼是整個新生代,要麼就是整個老年代,再要麼就是整個Java堆。而G1可以面向堆記憶體任何部分來組成回收集(Collection Set)進行回收,衡量標準不再是它屬於哪個分代,而 是哪塊記憶體中存放的垃圾數量最多,回收收益最大

G1回收器的特點

1. 並行與並行

  • 並行性:G1在回收期間,可以有多個GC執行緒同時工作,此時使用者執行緒Stop The World。
  • 並行性:G1擁有與應用程式交替執行的能力,部分工作可以和應用程式同時執行,因此,一般來說,不會在整個回收階段發生完全阻塞應用程式的情況。

2. 分代收集

  • G1也仍是遵循分代收集理論設計的,但其堆記憶體的佈局與其他收集器有非常明顯的差異:G1不再堅持固定大小以及固定數量的 分代區域劃分,而是把連續的Java堆劃分為多個大小相等的獨立區域(Region),每一個Region都可以根據需要,扮演新生代的Eden空間、Survivor空間,或者老年代空間。 收集器能夠對扮演不同角色的 Region採用不同的策略去處理,這樣無論是新建立的物件還是已經存活了一段時間、熬過多次收集的 舊物件都能獲取很好的收集效果。
  • Region中還有一類特殊的Humongous區域,專門用來儲存大物件。G1認為只要大小超過了一個 Region容量一半的物件即可判定為大物件。

3. 空間整合

  • G1在記憶體回收時以region作為基本單位,region之間使用複製演演算法,但整體上可看做是標記—壓縮演演算法。

4. 可預測的停頓時間模型

  • G1收集器能建立可預測的停頓時間模型,它將Region作為單次回收的最小單元,即每次收集到的記憶體空間都是Region大小的整數倍,這樣可以有計劃地避免 在整個Java堆中進行全區域的垃圾收集。
  • G1收集器去跟蹤各個Region裡面的垃圾堆積的「價值」大小,價值即回收所獲得的空間大小以及回收所需時間的經驗值,然後在後臺維護一 個優先順序列表,每次根據使用者設定允許的收集停頓時間,優先處理回收價值收益最大的那些Region。
  • 這種使用Region劃分記憶體空間,以及具有優先順序的區域回收方式,保證了G1收集器在有限的時間內獲 取儘可能高的收集效率。
  • 停頓預測模型是以衰減均值為理論基礎來實現的,在垃圾收集過程中,G1收集器會記 錄每個Region的回收耗時、每個Region記憶集裡的髒卡數量等各個可測量的步驟花費的成本,並分析得 出平均值、標準偏差、置信度等統計資訊。然後通過這些資訊預測現在開始回收的話,由 哪些Region組成回收集才可以在不超過期望停頓時間的約束下獲得最高的收益。

Region裡面存在的跨Region參照物件如何解決?

使用記憶集避免全堆作為GC Roots掃描,它的每個Region都維護有自己的記憶集,這些記憶集會記錄下別的Region 指向自己的指標,並標記這些指標分別在哪些卡頁的範圍之內。G1的記憶集在儲存結構的本質上是一 種雜湊表,Key是別的Region的起始地址,Value是一個集合,裡面儲存的元素是卡表的索引號。

G1收集器的運作過程

  • 初始標記(Initial Marking):僅僅只是標記一下GC Roots能直接關聯到的物件,並且修改TAMS 指標的值,讓下一階段使用者執行緒並行執行時,能正確地在可用的Region中分配新物件。這個階段需要 停頓執行緒,但耗時很短,而且是借用進行Minor GC的時候同步完成的,所以G1收集器在這個階段實際 並沒有額外的停頓。
  • 並行標記(Concurrent Marking):從GC Root開始對堆中物件進行可達性分析,遞迴掃描整個堆 裡的物件圖,找出要回收的物件,這階段耗時較長,但可與使用者程式並行執行。當物件圖掃描完成以 後,還要重新處理SATB記錄下的在並行時有參照變動的物件。
  • 最終標記(Final Marking):對使用者執行緒做另一個短暫的暫停,用於處理並行階段結束後仍遺留 下來的最後那少量的SATB記錄。
  • 篩選回收(Live Data Counting and Evacuation):負責更新Region的統計資料,對各個Region的回 收價值和成本進行排序,根據使用者所期望的停頓時間來制定回收計劃,可以自由選擇任意多個Region 構成回收集,然後把決定回收的那一部分Region的存活物件複製到空的Region中,再清理掉整個舊 Region的全部空間。這裡的操作涉及存活物件的移動,是必須暫停使用者執行緒,由多條收集器執行緒並行 完成的。

在這裡插入圖片描述

7種經典垃圾回收器的比較

在這裡插入圖片描述

垃圾回收器組合

在這裡插入圖片描述

低延遲垃圾收集器

Shenandoah收集器

Shenandoah也是使用基於Region的堆記憶體佈局,同樣 有著用於存放大物件的Humongous Region,預設的回收策略也同樣是優先處理回收價值最大的 Region……但在管理堆記憶體方面,它與G1至少有三個明顯的不同之處。

  • G1的回收階段是可以多執行緒並行的,但卻不能與使用者執行緒並行,Shenandoah支援並行的整理演演算法。
  • 預設不使用分代收集的,換言之,不會有 專門的新生代Region或者老年代Region的存在,沒有實現分代,並不是說分代對Shenandoah沒有價值, 這更多是出於價效比的權衡,基於工作量上的考慮而將其放到優先順序較低的位置上。
  • Shenandoah摒棄了在G1中耗費大量記憶體和計算資源去維護的記憶集,改用名為「連線矩陣」的全域性資料結構來記錄跨Region的參照關係,降低了處理跨代指標時的記憶集維護消耗,也降 低了偽共用問題的發生概率。連線矩陣可以簡單理解為一張二維表格,如果Region N有 物件指向Region M,就在表格的N行M列中打上一個標記,在回收時通過這張表格就可以得出哪些Region之間產生了跨代參照。

Shenandoah收集器的工作過程大致可以劃分為以下九個階段:

  1. 初始標記:與G1一樣,首先標記與GC Roots直接關聯的物件,這個階段仍 是「Stop The World」的,但停頓時間與堆大小無關,只與GC Roots的數量相關。
  2. 並行標記:與G1一樣,遍歷物件圖,標記出全部可達的物件,這個階段 是與使用者執行緒一起並行的,時間長短取決於堆中存活物件的數量以及物件圖的結構複雜程度。
  3. 最終標記:與G1一樣,處理剩餘的SATB掃描,並在這個階段統計出回收價值 最高的Region,將這些Region構成一組回收集。最終標記階段也會有一小段短暫的停頓。
  4. 並行清理:這個階段用於清理那些整個區域內連一個存活物件都沒有找到 的Region。
  5. 並行回收:在這個階段,Shenandoah要把回收集裡面的存活物件先複製一份到其他未被使用的Region之 中。並行回收階段執行的時間長短取決於回收集的大小。
  6. 初始參照更新:並行回收階段複製物件結束後,還需要把堆中所有指 向舊物件的參照修正到複製後的新地址,這個操作稱為參照更新。參照更新的初始化階段實際上並未 做什麼具體的處理,設立這個階段只是為了建立一個執行緒集合點,確保所有並行回收階段中進行的收 集器執行緒都已完成分配給它們的物件移動任務而已。初始參照更新時間很短,會產生一個非常短暫的 停頓。
  7. 並行參照更新:真正開始進行參照更新操作,這個階段是與使用者 執行緒一起並行的,時間長短取決於記憶體中涉及的參照數量的多少。並行參照更新與並行標記不同,它 不再需要沿著物件圖來搜尋,只需要按照記憶體實體地址的順序,線性地搜尋出參照型別,把舊值改為 新值即可。
  8. 最終參照更新:解決了堆中的參照更新後,還要修正存在於GC Roots 中的參照。這個階段是Shenandoah的最後一次停頓,停頓時間只與GC Roots的數量相關。
  9. 並行清理:經過並行回收和參照更新之後,整個回收集中所有的Region已 再無存活物件,這些Region都變成Immediate Garbage Regions了,最後再呼叫一次並行清理過程來回收 這些Region的記憶體空間,供以後新物件分配使用。

ZGC收集器

ZGC和Shenandoah的目標是高度相似的,都希望在儘可能對吞吐量影響不太大的前提下,實現在任意堆記憶體大小下都可以把垃圾收集的停頓時間限制在十毫秒以內的低延遲。

ZGC收集器是一款基於Region記憶體佈局的,(暫時) 不設分代的,使用了讀屏障、染色指標和記憶體多重對映等技術來實現可並行的標記-整理演演算法的,以低 延遲為首要目標的一款垃圾收集器。

ZGC也採用基於Region的堆記憶體佈局,但 與它們不同的是,ZGC的Region具有動態性——動態建立和銷燬,以及動態的區域容量大小。

ZGC的運作過程可分為四個階段:

  1. 並行標記(:與G1、Shenandoah一樣,並行標記是遍歷物件圖做可達性分析的 階段,前後也要經過類似於G1、Shenandoah的初始標記、最終標記(儘管ZGC中的名字不叫這些)的 短暫停頓,而且這些停頓階段所做的事情在目標上也是相類似的。與G1、Shenandoah不同的是,ZGC 的標記是在指標上而不是在物件上進行的,標記階段會更新染色指標中的Marked 0、Marked 1標誌位。
  2. 並行預備重分配:這個階段需要根據特定的查詢條件統計得出 本次收集過程要清理哪些Region,將這些Region組成重分配集。
  3. 並行重分配:重分配是ZGC執行過程中的核心階段,這個過程要把重分 配集中的存活物件複製到新的Region上,併為重分配集中的每個Region維護一個轉發表,記錄從舊物件到新物件的轉向關係。
  4. 並行重對映:重對映所做的就是修正整個堆中指向重分配集中舊物件的所 有參照。ZGC很巧妙地把並行重對映 階段要做的工作,合併到了下一次垃圾收集迴圈中的並行標記階段裡去完成,反正它們都是要遍歷所 有物件的,這樣合併就節省了一次遍歷物件圖的開銷。一旦所有指標都被修正之後,原來記錄新舊 物件關係的轉發表就可以釋放掉了。

選擇合適的垃圾收集器

考慮以下三個問題:

應用程式的主要關注點是什麼?

  • 如果是資料分析、科學計算類的任務,目標是能儘快算出結果, 那吞吐量就是主要關注點;
  • 如果是SLA應用,那停頓時間直接影響服務品質,嚴重的甚至會導致事務 超時,這樣延遲就是主要關注點;
  • 而如果是使用者端應用或者嵌入式應用,那垃圾收集的記憶體佔用則是 不可忽視的。

執行應用的基礎設施如何?

  • 硬體規格,要涉及的系統架構是x86-32/64、SPARC還是 ARM/Aarch64;
  • 處理器的數量多少,分配記憶體的大小;
  • 選擇的作業系統是Linux、Solaris還是Windows 等。

使用JDK的發行商是什麼?版本號是多少?

是ZingJDK/Zulu、OracleJDK、Open-JDK、OpenJ9抑 或是其他公司的發行版?該JDK對應了《Java虛擬機器器規範》的哪個版本?

怎樣選擇垃圾回收器

  • 優先調整堆的大小讓JVM自適應完成。
  • 如果記憶體小於100M,使用序列收集器
  • 如果是單核、單機程式,並且沒有停頓時間的要求,序列收集器
  • 如果是多CPU、需要高吞吐量、允許停頓時間超過1秒,選擇並行或者JVM自己選擇
  • 如果是多CPU、追求低停頓時間,需快速響應(比如延遲不能超過1秒網際網路應用),使用並行收集器

推薦學習:《》

以上就是詳細介紹Java虛擬機器器:JVM垃圾回收器的詳細內容,更多請關注TW511.COM其它相關文章!