JDK8垃圾回收調優指南--(9)G1

原文:Java Platform, Standard Edition HotSpot Virtual Machine Garbage Collection Tuning Guide--Garbage First Garbage Collector

G1垃圾收集器是一種服務器風格的垃圾收集器,針對的是內存較大的多處理器機器。它試圖在滿足GC停頓時間目標的同時,高概率的實現高吞吐量。整個堆操作(例如'global marking')是與應用線程併發執行的。這可以防止與堆大小或實時數據大小成比例的中斷。

G1收集器通過多種技術實現了高性能和GC停頓時間的目標。

堆被劃分爲一組大小相同的堆區域,每個區域都是一個連續的虛擬內存。G1執行一個'concurrently global marking phase'(併發的全局標記階段)來確定堆中對象的活性。標記階段完成後,G1知道哪些區域大部分是空的。它首先收集這些區域,這通常會產生大量的自由空間。這就是爲什麼這種垃圾收集方法稱爲'Garbage-First'(垃圾優先)。顧名思義,G1將其收集和壓縮活動集中在堆中可能充滿可回收對象(即垃圾)的區域。G1使用一個“暫停預測模型”來滿足用戶定義的暫停時間目標,並基於暫停時間目標選擇要收集的區域數量。

G1將對象從堆的一個或多個區域複製到堆上的一個區域,並在此過程中壓縮和釋放內存。在多處理器上並行執行這種轉移,以減少停頓時間並增加吞吐量。因此,每次垃圾收集時,G1都在不斷地減少碎片。這超出了前面兩種方法(CMS和並行)的能力。CMS(併發標記清除)垃圾收集不做壓縮。並行收集器壓縮只執行全堆壓縮,這會導致相當長的停頓時間。

需要注意的是G1不是一個實時收集器。它可以高概率地滿足設定的停頓時間目標,但並不絕對。根據之前回收的數據,G1會預估在目標時間內可以回收多少個區域。因此,收集器對正在回收的區域的回收成本有一個相當準確的模型,它使用這個模型來確定在停頓時間目標內收集哪些區域和多少區域。

G1的第一個關注點就是爲那些運行高內存,低GC延遲的應用用戶提供一個解決方案。這意味着約爲6gb或更大的堆,且穩停頓時間穩定在0.5秒以下。

如果應用程序具有以下一個或多個特性,那麼使用CMS或並行壓縮的應用程序將受益於切換到G1。

  • 超過50%的Java堆被存活數據佔用。
  • 對象分配率或提升率差異顯著。
  • 應用程序正在經歷不必要的長時間垃圾收集或壓縮暫停(超過0.5到1秒)。

G1計劃作爲CMS的長期替代品。將G1與CMS進行比較,可以發現G1與CMS之間的差異,從而使G1成爲更好的解決方案。
一個不同之處在於G1是一個壓縮收集器。此外,G1提供了比CMS收集器更穩定且可預測的GC停頓,並允許用戶指定所需的暫停目標。

與CMS一樣,G1是爲需要更短GC停頓的應用設計的。

G1將堆劃分爲固定大小的區域(灰色框),如圖9-1所示:

Heap Division by G1

G1在邏輯上是分代的。一組空區域被指定爲邏輯年輕代。在圖中,年輕代是淺藍色的。分配是在邏輯年輕代之外完成的,當年輕代已滿時,將對該區域集進行垃圾收集(年輕代收集)。在某些情況下,可以同時收集年輕區域集之外的區域(深藍色的舊區域)。這被稱爲'mixed collection'。在圖中,正在收集的區域用紅色框標記。圖中顯示了一個'mixed collection',因爲同時收集了年輕域和老年區域。G1是一個壓縮收集,它將活動對象複製到選定的、最初爲空的區域。根據存活對象的年齡,可以將對象複製到存活區域(用“S”標記)或舊區域(沒有特別顯示)。以“H”爲標記的區域含有大對象,超過了區域的一半,並經過特殊處理;詳見Humongous Objects and Humongous Allocations

Allocation Failure

與CMS一樣,G1在應用程序運行時併發地完成其收集的部分內容,並且存在應用程序分配對象的速度快於垃圾收集器恢復空閒空間的風險。有關類似的CMS行爲,請參閱併發模式故障。在G1中,類似的故障發生在G1將存活數據從一個區域複製到另一個區域時(耗盡Java堆)。複製是爲了壓縮存活的數據。如果在回收過程中找不到空閒(空)區域,則會發生分配失敗(因爲沒有空間來分配正在被轉移區域中的存活對象),此時'stop-the-world'(STW),完成'full collection'。

Floating Garbage

對象可能在G1收集期間死亡而無法收集。G1使用了一種名爲'snapshot-at-the-beginnint'(SATB)的技術,以確保垃圾收集器能夠找到所有存活的對象。SATB聲明,爲了回收的目標,在併發標記開始時存活的任何對象(整個堆上的標記)都被認爲是存活的。SATB允許浮動垃圾,其方式類似於CMS增量更新。

Pauses

G1暫停應用,將存活對象複製到新區域。這些暫停可以是隻收集年輕區域的'young collection'暫停,也可以是回收年輕區域和老年區域的'mixed collection'暫停。與CMS一樣,當應用程序停止時,會有一個'final pause'或'remark pause'來完成標記。
CMS也有一個初始標記暫停,G1將'initial mark'作爲轉移暫停的一部分。G1在一次回收的末尾會有一個清理階段,部分是STW,部分是併發的。STW部分的清理階段標識空區域,並確定下一次回收的候選老年區域。

Card Tables and Concurrent Phases

如果垃圾收集器沒有收集整個堆(增量收集),那麼垃圾收集器需要知道從堆的未收集部分到正在收集的堆部分的指針在哪裏。這通常適用於一個分代垃圾收集器,在分代垃圾收集器中,堆的未收集部分通常是老年代,而堆的收集部分是年輕代。保存這些信息的數據結構(老年代指針指向年輕代對象)是一個'remembered set'。'card table'是'remembered set'的一種特殊類型。
Java HotSpot VM使用字節數組作爲'card table'。每個字節都被稱爲'card'。'card'對應於堆中的一組地址。將卡片弄髒意味着將字節的值更改爲髒值;髒值可能包含老年代到年輕代的新指針,位於卡片覆蓋的地址範圍內。

處理'card'意味着查看'card',看看是否有老年代到年輕代的指針,並可能對這些信息進行處理,比如將其轉化成另一個數據結構。

G1有併發標記階段,標記應用中的存活對象。併發標記從轉移暫停的末尾階段(初始標記工作在此完成)延伸到remark。
併發清理階段將回收清空的區域添加到空閒區域列表中,並清除這些區域的'remembered set'。此外,併發優化線程根據需要運行,以處理被應用程序寫入弄髒的、可能具有跨區域引用的'card table'條目。

Starting a Concurrent Collection Cycle

如前所述,在'mixed collection'中的年輕區域和老年區域都會被回收。爲了收集老年區域,G1對堆中的存活對象做了一次完整的標記。這種標記由併發標記階段完成。當整個Java堆的佔用率達到參數'InitiatingHeapOccupancyPercent'的值時,將啓動併發標記階段。使用命令行選項'-XX:InitiatingHeapOccupancyPercent=<NN>'設置此參數的值。佔有率'InitiatingHeapOccupancyPercent'的默認值是45。

Pause Time Goal

使用'MaxGCPauseMillis'爲G1設置暫停時間目標。G1使用一個預測模型來決定在目標暫停時間內可以完成多少垃圾回收工作。在回收結束時,G1選擇下一次回收中將要回收的區域(the collection set)。'collection set'將包含年輕區域('collection set'大小的和決定邏輯年輕代的大小)。G1控制GC停頓的長短,部分原因是通過選擇回收集中年輕區域的數量。與其它垃圾收集器一樣,您可以在命令行上指定年輕代的大小,但是這樣做可能會妨礙G1實現目標GC停頓時間的能力。除了停頓時間目標之外,還可以指定暫停發生的時間段長度。您可以指定使用此時間跨度(GCPauseIntervalMillis)和暫停時間目標的最小mutator使用量。'MaxGCPauseMillis'的默認值是200毫秒。GCPauseIntervalMillis(0)的默認值相當於對時間跨度沒有要求。

友情提示:最後一段垮掉了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章