G1Introduct_cn

surpassLiang發表於2020-10-22

G1垃圾回收機入門

原文網站

概述

目的

這篇文章涵蓋了G1垃圾收集器的基本用法以及它被用於HotspotJVM的方式。您將瞭解G1收集器的內部工作原理、使用G1的關鍵命令列開關以及記錄其操作的選項。

閱讀時長

接近一小時

簡介

這篇文件介紹了Java虛擬機器(JVM)G1垃圾收集(GC)的基本知識。在本文的第一部分是對JVM伴隨垃圾回收器效能的概述。接下來我們回顧CMS收集器如何與hotspotJVM協同工作。然後,我們通過HotspotJVM上的G1垃圾收集器逐步介紹垃圾收集器的工作原理。在接下來的一個部分,介紹G1垃圾收集器中可用的垃圾收集命令列選項。最後,您將瞭解與G1收集器一起使用的日誌記錄選項。

軟硬體需求

以下是硬體和軟體要求列表:

  • 需要在Windows XP或更高版本的PC上執行。請注意,實際操作是在Windows7上完成的,但是並沒有在所有平臺上進行測試。不過,在OSX或Linux上一切都應該可以正常工作。此外,最好使用至少一個機芯。
  • Java 7 Update 9 or later
  • 最新的Java7演示和示例Zip檔案

先決條件

在開始本教程之前,您應該:

  • 如果您還沒有這樣做,請下載並安裝最新版本的javajdk(jdk7u9或更高版本)。
    Java 7 JDK Downloads
  • 從相同的位置下載和安裝示例。解壓縮檔案並將內容放入目錄中。例如:C:\javademos

Java技術與JVM

Java概述

Java概述

Java是sunmicrosystems於1995年首次釋出的一種程式語言和計算平臺。它是驅動Java程式(包括實用程式、遊戲和業務應用程式)的底層技術。Java在全球超過8.5億臺個人電腦上執行,在全球數十億臺裝置上執行,包括移動裝置和電視裝置。Java是由許多關鍵元件組成的,這些元件作為一個整體,建立了Java平臺。

Java執行時版

下載Java時,您將獲得Java執行時環境(JRE)。JRE由Java虛擬機器(JVM)、Java平臺核心類和支援Java平臺庫組成。在您的計算機上執行Java應用程式需要這三種方法。在Java7中,Java應用程式從作業系統作為桌面應用程式執行,作為桌面應用程式但使用Java Web Start從Web安裝,或作為瀏覽器中的Web嵌入式應用程式(使用JavaFX)執行。

Java程式語言

Java是一種物件導向的程式語言,它包括以下特性。

  • 平臺獨立性——Java應用程式被編譯成位元組碼,位元組碼儲存在類檔案中並載入到JVM中。由於應用程式在JVM中執行,所以它們可以在許多不同的作業系統和裝置上執行。
  • 物件導向——java是一種面嚮物件語言,它具有C++和C++的許多特性並改進了它們。
  • 自動垃圾收集——Java自動分配和釋放記憶體,這樣程式就不必處理這個任務。
  • 豐富的標準庫—— Java包含大量可用於執行輸入/輸出、聯網和日期操作等任務的預製物件。

Java開發工具包

java開發工具包(JDK)是用於開發Java應用程式的工具集合。使用JDK,您可以編譯用Java程式語言編寫的程式,並在JVM中執行它們。此外,JDK還提供了打包和分發應用程式的工具。

JDK和JRE共享Java應用程式程式設計介面(javaapi). javaapi是開發人員用來建立Java應用程式的預打包庫的集合。javaapi通過提供工具來完成許多常見的程式設計任務,包括字串操作、日期/時間處理、聯網和實現資料結構(例如,列表、對映、堆疊和佇列),使開發變得更加容易。

Java 虛擬機器(JVM)

Java虛擬機器(JVM)是一種抽象計算機器。JVM是一個程式,對於編寫在其中執行的程式來說,它看起來像一臺機器。這樣,Java程式就被寫入同一組介面和庫中。針對特定作業系統的每個JVM實現都將Java程式設計指令轉換為在本地作業系統上執行的指令和命令。這樣,Java程式就實現了平臺獨立性。

第一個Java虛擬機器的原型實現是由Sun Microsystems, Inc.完成的,它模擬了Java虛擬機器指令集,該軟體由一個類似於當代個人數字助理(PDA)的手持裝置託管。Oracle當前的實現在移動裝置、桌面裝置和伺服器裝置上模擬Java虛擬機器,但Java虛擬機器不採用任何特定的實現技術、主機硬體或主機作業系統。它不是固有的解釋,但也可以通過編譯其指令集為矽CPU來實現。它也可以在微碼或直接在矽中實現。

Java虛擬機器對Java程式語言一無所知,只知道一種特殊的二進位制格式,類檔案格式。類檔案包含Java虛擬機器指令(位元組碼)和符號表以及其他輔助資訊。

為了安全起見,Java虛擬機器對類檔案中的程式碼施加了強大的語法和結構約束。然而,任何具有可用有效類檔案表示的功能的語言都可以由Java虛擬機器託管。被一個普遍可用的、獨立於機器的平臺所吸引,其他語言的實現者可以將Java虛擬機器作為其語言的傳遞工具。

探索JVM架構

Hotspot 架構

jvm_Architecture.PNG

JVM的主要元件包括類載入器、執行時資料區域和執行引擎。

Key Hotspot Components

JVM中與效能相關的關鍵元件在下圖中高亮顯示。

key_hotspot_jvm_components

在優化效能時,JVM有三個元件是重點關注的。是儲存物件資料的地方,該區域由啟動時選擇的垃圾回收器管理。大多數優化選項都與調整堆大小和為您的情況選擇最合適的垃圾收集器有關。JIT編譯器對效能也有很大的影響,但很少需要對JVM的較新版本進行調優。

效能基礎

通常,在調優Java應用程式時,重點放在兩個主要目標之一:響應性或吞吐量。隨著教程的進展,我們將回顧這些概念。

響應性

響應性是指應用程式或系統對請求的資料段作出響應的速度。示例包括:

  • 桌面UI響應事件的速度
  • 網站返回頁面的速度的快慢
  • 資料庫查詢返回的速度

For applications that focus on responsiveness, large pause times are not acceptable. The focus is on responding in short periods of time.

對於專注於響應性的應用程式,比較長的停頓時間是不可接受的。重點是在短時間內做出反應。

吞吐量

吞吐量的重點是在特定時間段內使應用程式的工作量最大化。衡量吞吐量的示例包括:

  • 在給定時間內完成的事務數。
  • 批處理程式在一小時內可以完成的作業數。
  • 一小時內可以完成的資料庫查詢數。

對於關注吞吐量的應用程式來說,高暫停時間是可以接受的。由於高吞吐量應用程式關注的是較長時間內的基準測試,因此不考慮快速響應時間。

G1 垃圾收集器

G1 垃圾收集器

Garbage-First(Garbage First,G1)收集器是一種伺服器風格的垃圾收集器,針對具有大記憶體和多處理器計算機。它極大程度的滿足垃圾收集(GC)暫停時間目標,同時實現高吞吐量。G1垃圾收集器在Oracle JDK 7 update 4和更高版本中完全受支援。G1採集器專為以下應用而設計:

  • 像CMS收集器一樣可以和應用程式併發執行。
  • 壓縮空閒的空間無需漫長的停頓時間。
  • 更需要可預測的GC暫停持續時間。
  • 不想犧牲很多吞吐量效能。
  • 不需要更大的Java堆。

G1致力於並行標記掃描採集器(CMS)的長期替代品。G1相比於CMS垃圾收集器,最大區別是G1具有更好的解決方案。一個區別是G1是一個可壓縮收集器。G1進行了充分的壓縮,以完全避免使用細粒度的自由列表進行分配,而是依賴於區域。這大大簡化了收集器的各個部分,並且基本上消除了潛在的碎片問題。此外,G1提供了比CMS收集器更可預測的垃圾收集暫停,並允許使用者指定所需的暫停目標。

G1 操作概述

舊的垃圾收集器(序列、並行、CMS)都將堆結構分為三個部分:年輕代、老年代和固定記憶體大小的永久代。

HeapStructure

所有的記憶體物件都在這三個部分中的一個。

G1收集器採用不同的方法。

g1_heap_allocation

堆被劃分為一組大小相等的堆區域,每個區域都是一個連續的虛擬記憶體範圍。某些區域集被分配與舊收集器中相同的角色(eden、survivor、old),但它們沒有固定的大小。這為記憶體使用提供了更大的靈活性。

在執行垃圾收集時,G1的操作方式與CMS收集器類似。G1執行一個併發的全域性標記階段,以確定整個堆中物件的活躍度。標記階段完成後,G1知道哪些區域大部分是空的。它首先在這些區域聚集,這通常會產生大量的自由空間。這就是為什麼這種垃圾收集方法被稱為垃圾優先。顧名思義,G1將其收集和壓縮活動集中在堆中可能充滿可回收物件(即垃圾)的區域。G1使用暫停預測模型來滿足使用者定義的暫停時間目標,並根據指定的暫停時間目標選擇要收集的區域數。

G1確定的適合復墾的區域採用疏散法進行垃圾收集。G1將物件從堆的一個或多個區域複製到堆上的單個區域,並在此過程中壓縮和釋放記憶體。這種疏散在多處理器上並行執行,以減少暫停時間並提高吞吐量。因此,在每次垃圾收集中,G1都會在使用者定義的暫停時間內連續工作以減少碎片。這超出了前面兩種方法的能力。CMS(併發標記清除)垃圾回收器不進行壓縮。ParallelOld垃圾回收只執行整個堆壓縮,這會導致相當長的暫停時間。

需要注意的是,G1不是實時收集器。它很有可能達到設定的暫停時間目標,但不是絕對確定的。根據一個使用者在一個目標區域內收集到多少個資料,可以根據指定的時間段內收集多少個資料。因此,收集器有一個相當精確的區域收整合本模型,它使用該模型來確定在暫停時間目標內要收集哪些區域以及收集多少區域。

Note: G1既有併發(與應用程式執行緒一起執行,例如,細化、標記、清理)和並行(多執行緒,例如stop the world)階段。完整的垃圾收集仍然是單執行緒的,但是如果調整得當,您的應用程式應該避免使用完整的gc。

G1 Footprint

如果從parallelloldgc或CMS收集器遷移到G1,您可能會看到更大的JVM程式大小。這在很大程度上與“會計”資料結構(如記憶集和收集集)有關。

記憶集或RSets將物件引用跟蹤到給定區域。堆中每個區域有一個RSet。RSet支援區域的並行和獨立集合。資源集的總體足跡影響小於5%。

集合集或CSets將在GC中收集的區域集。在GC期間,CSet中的所有實時資料都會被清空(複製/移動)。區域集可以是伊甸園、倖存者和或者老年代。CSets對JVM大小的影響不到1%。

G1的推薦用例

G1的第一個重點是為執行需要大量堆且GC延遲有限的應用程式的使用者提供一個解決方案。這意味著堆大小約為6GB或更大,並且穩定且可預測的暫停時間低於0.5秒。

如果應用程式具有以下一個或多個特徵,那麼使用CMS或parallelloldgc垃圾回收器執行的應用程式將有助於切換到G1。

  • 完整的GC持續時間太長或太頻繁。
  • 物件分配率或提升率差異顯著。
  • 意外的長時間垃圾收集或壓縮暫停(超過0.5到1秒)

Note: 如果您使用的是CMS或ParallelOldGC,並且您的應用程式沒有經歷長時間的垃圾收集暫停,那麼您可以繼續使用當前的收集器。使用最新的JDK並不要求更改為G1收集器。

回顧常用的垃圾收集器和CMS

回顧常用的垃圾收集器和CMS

併發標記-清除(CMS)收集器(也稱為併發低暫停收集器)收集持久代。它試圖通過與應用程式執行緒同時執行大部分垃圾回收工作來儘量減少由於垃圾回收而導致的暫停。通常併發低暫停收集器不會複製或壓縮活動物件。垃圾收集是在不移動活動物件的情況下完成的。如果碎片化成為一個問題,分配一個更大的堆。

Note: 年輕一代的CMS收集器使用與並行收集器相同的演算法。

CMS收集階段

CMS收集器對舊一代堆執行以下階段:

PhaseDescription
(1) 初識標記 (STW )老一代中的物件被“標記”為可到達的,包括那些從年輕一代可以到達的物件。與次要收集暫停時間相比,暫停時間通常較短。
(2) 併發標記在執行Java應用程式執行緒時,同時遍歷可訪問物件的保留生成物件圖。從標記的物件開始掃描,並傳遞性地標記所有可從根訪問的物件。在併發階段2、3和5中執行賦值函式,並且在這些階段中分配給CMS生成的任何物件(包括提升的物件)都會立即標記為活動的。
(3) 標記 (STW)查詢由於併發收集器完成跟蹤物件後Java應用程式執行緒對物件的更新而在併發標記階段丟失的物件。
(4) 併發清除收集在標記階段標識為不可訪問的物件。死物件的集合會將物件的空間新增到空閒列表中,以便以後分配。在這一點上,死物體可能會合並。請注意,活動物件不會被移動。
(5) 重設階段通過清除資料結構為下一次併發收集做好準備。

檢視垃圾收集步驟

接下來,讓我們一步一步地回顧CMS收集器的操作。

1.CMS收集器的堆結構

堆被分成三個空間。

cms_heap_structure
年輕代被分成伊甸園和兩個倖存者空間。老年代是一個連續的空間。物件收集已完成。除非有完整的GC,否則不進行壓實。

2.年輕代GC如何在CMS中工作

年輕代是淺綠色的,老年代是藍色的。如果你的應用程式已經執行了一段時間,這就是CMS的樣子。物件散落在老年代區域。

how_young_gc_works
使用CMS,老年代物件被釋放到適當的位置。它們不會被移動。除非有完整的GC,否則空間不會被壓縮。

3. 年輕代收集

存活物件從Eden空間和倖存者空間複製到另一個倖存者空間。任何已達到老年代閾值的舊物件都將升級到老年代。

young_generation_collection
4. Young GC之後

在Young GC過後,Eden區域和一個survivor區域被清除。

after_young_gc
新升級的物件在圖表上以深藍色顯示。綠色物件是尚未被提升到老年代的倖存的年輕代物件。
5. CMS收集老年代
兩個STW事件發生:初始標記和標記階段。當老年代達到一定比率時,啟動CMS。
old_gen_collection_in_cms
(1) 初始標記是標記活動(可到達)物件的短暫暫停階段。(2) 併發標記在應用程式繼續執行時查詢活動物件。最後,在(3)備註階段,發現前一階段(2)併發標記過程中遺漏的物件。

6. 老年代收集-並行掃描

上一階段未標記的物件將就地釋放。沒有壓縮。
old_gen_collection_concurrent_sweep
Note: 未標記的物件就等於死物件

7. 老年代收集器 - 事後清除

在(4)掃描階段之後,您可以看到大量記憶體被釋放。您還將注意到沒有進行壓縮。

old_gen_collection_after_sweeping

最後,CMS收集器將通過(5)重置階段並等待下一次達到GC閾值。

逐步分析G1垃圾收集器

逐步分析G1垃圾收集器

G1收集器採用不同的方法來分配堆。下面的圖片一步步回顧G1系統。

1. G1堆結構

堆是一個記憶體區域,分成許多固定大小的區域。.

g1_heap_structure

區域大小由JVM在啟動時選擇。JVM的目標大小通常設定2000個區域,每個區域為1到32MB。

2. G1堆分配

在實際過程中,這個區域對映到邏輯形式展現的Eden、Survivor區域和老年代區域。

g1_heap_allocation

圖片中的顏色顯示了哪個區域與哪個角色相關聯。存活物件從一個區域疏散到另一個區域(即複製或移動)。區域被設計成與所有其他應用程式執行緒並行收集,也可以不停止所有其他應用程式執行緒。

如圖所示,區域可以被分配到伊甸園、倖存者和老年代區域。此外,還有第四種型別的物件被稱為巨大的區域。這些區域被設計用來容納大小為標準區域50%或更大的物件。它們儲存為一組連續的區域。最後一種型別的區域是堆中未使用的區域。

Note: 在寫這篇文章的時候,收集巨大的物件還沒有得到優化。因此,應該避免建立這種大小的物件。

3. G1眼中的年輕代

堆被分成大約2000個區域。最小大小為1Mb,最大大小為32Mb。藍色區域包含老年代物件,綠色區域包含年輕代物件。

young_generation_in_g1

請注意,這些區域不需要像舊的垃圾收集器那樣是連續的。

4. A G1眼中的Young GC

存活物件被疏散(即複製或移動)到一個或多個倖存者區域。如果滿足老年代閾值,則某些物件將升級到老年代區域。

a_young_gc_in_g1

這是一個(STW)暫停。計算下一個年輕GC的Eden大小和倖存者大小。會計資訊被儲存以幫助計算大小。像暫停時間目標這樣的事情也被考慮在內。

這種方法可以很容易地調整區域的大小,根據需要使它們變大或變小。

5. G1眼中的young GC結尾

存活物件被疏散到倖存者區或老一代地區。

end_of_young_gc_with_g1

最近升級的物件以深藍色顯示。倖存者區域為綠色。

綜上所述,關於G1的年輕代可以這樣說:

  • 堆是一個被分割成多個區域的單個記憶體空間。

  • 年輕代記憶體是由一組非連續區域組成的。這使得在需要時可以很容易地調整大小。

  • 年輕代的垃圾收集,或young gc,是STW的事件,該操作將停止所有應用程式執行緒。

  • 年輕的GC是使用多個執行緒並行完成的。

  • 存活物件被複制到新的倖存者或舊一代區域。

G1眼中的老年代收集

與CMS收集器一樣,G1收集器被設計為老一代物件的低暫停收集器。下表描述了老一代的G1收集階段。

G1採集階段-並行標記週期階段

G1收集器對老年代堆執行以下階段。請注意,有些階段是年輕代收集的一部分。

PhaseDescription
(1) 初識標記(STW)這是一個STW事件。在G1中,它搭載在一個正常的年輕GC上。標記倖存者區域(根區域),這些區域可能引用老年代中的物件。
(2) 根節點掃描掃描倖存者區域,尋找老年代的參考。當應用程式繼續執行時會發生這種情況。該階段必須在年輕GC出現之前完成。
(3) 併發標記在整個堆上查詢存活物件。這是在應用程式執行時發生的。年輕代垃圾回收可以中斷此階段。
(4) 重新標記(STW)完成堆中活動物件的標記。使用一種稱為“開始時快照”(SATB)的演算法,該演算法比CMS收集器中使用的演算法快得多。
(5) 清除(STW 和併發)*對活動物件和完全自由區域執行記帳。(停止世界)清理記憶中的場景。(停止世界)重置空白區域並將其返回到空閒列表。(並行)
(6) 複製(STW)這些是停止世界暫停以疏散或複製活動物件到新的未使用區域。這可以通過記錄為“[GC pause(young)]”的年輕代區域來實現。或同時記錄為“[GC Pause(mixed)]”的年輕代和老一代區域。

G1 逐步分析老年代收集器

定義了階段之後,讓我們看看它們是如何與G1收集器中的老年代互動的。

6.初識標記

存活物件的初始標記是在年輕代垃圾收集上進行的。在日誌中,這被記為 GC pause (young)(inital-mark).

initial_marking_phase

7. 併發標記階段

如果發現空區域(用“X”表示),則在備註階段立即將其刪除。此外,還計算了決定活躍度的“會計”資訊。

concurrent_marking_phase

8. 標記階段

刪除並回收空區域。現在將計算所有區域的區域活動度。

remark_phase

9. 複製/清理階段

G1選擇“活躍度”最低的區域,也就是可以收集最快的區域。然後這些區域在年輕GC的同時被收集。這在日誌中表示為“[GC pause(mixed)]”。所以年輕代和老年代同時被收集。

copying_cleanup_phase

10. 複製/清理階段後

所選區域已被收集並壓縮為圖中所示的深藍色區域和深綠色區域。

after_copying_cleanup_phase

老年代收集器綜述

總之,對於老一代的G1垃圾回收,我們可以提出幾個關鍵點。

  • 併發標記階段

  • 在應用程式執行時併發計算活動資訊。

  • 此活動資訊確定在疏散暫停期間,哪些區域最適合回收。

  • 像CMS一樣並沒有清除階段。

  • 重新標記階段

  • 使用快照開始(SATB)演算法,比CMS使用的演算法快得多。

  • 完全空的區域被回收。

  • 複製/清理階段

    • 年輕代和老年代同時再生。

    • 老年代區域根據其活躍程度進行選擇。

命令列選項和最佳實踐

命令列選項和最佳實踐

在本節中,讓我們看看G1的各種命令列選項。

基本的命令列

啟用G1收集器使用如下命令: -XX:+UseG1GC

下面是一個示例命令列,用於啟動JDK演示和示例下載中包含的Java2Demo:

java -Xmx50m -Xms50m -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -jar c:\javademos\demo\jfc\Java2D\Java2demo.jar

關鍵命令列開關

-XX:+UseG1GC - 告訴JVM使用G1垃圾收集器。

-XX:MaxGCPauseMillis=200 - 設定最大GC暫停時間的目標。這是一個軟目標,JVM將盡力實現它。因此,有時無法達到暫停時間目標。預設值為200毫秒。

-XX:InitiatingHeapOccupancyPercent=45 - 啟動併發GC迴圈的(整個)堆佔用率的百分比。G1使用它來觸發基於整個堆(而不僅僅是一個代)佔用率的併發GC迴圈。值為0表示“do constant GC cycles”。預設值為45%(即45%已滿或已佔用)。

最佳實踐

在使用G1時,您應該遵循一些最佳實踐。

不要設定年輕代的大小

通過“-Xmn”顯式設定年輕代大小會影響G1收集器的預設行為。

  • G1將不再考慮集合的暫停時間目標。因此,從本質上講,設定年輕代的規模會禁用暫停時間目標。
  • G1已經無法根據需要擴大和收縮年輕代的空間。由於大小是固定的,因此無法更改大小。

響應時間指標

不要將平均響應時間(ART)用作設定XX:MaxGCPausEmilis=<N>’的度量,而應考慮設定將滿足90%或更多時間目標的值。這意味著90%的使用者提出請求不會經歷比目標更高的響應時間。記住,暫停時間是一個目標,不一定總是被滿足的。

什麼是疏散失敗?

在GC期間,對於倖存者和提升物件,當JVM用完堆區域時發生的提升失敗。堆無法擴充套件,因為它已達到最大值。在使用“-XX:+PrintGCDetailsby**到空間溢位`**”時,GC日誌中會指出這一點。代價太昂貴了!

  • GC仍然需要繼續,因此必須釋放空間。
  • 複製失敗的物件必須保留在原位。
  • 對CSet中區域資源集的任何更新都必須重新生成。
  • 所有這些步驟都很昂貴。

如何避免疏散失敗

為避免疏散失敗,請考慮以下選項。

  • 增加堆大小

    • 增加**-XX:G1ReservePercent=n**,預設值為10。

    • G1試圖讓保留記憶體空閒以防需要更多的“空間”,從而建立了一個假上限。

  • 提前開始標記迴圈

  • 使用**-XX:congcthreads=n**選項增加標記執行緒的數量。

G1垃圾收集器的完整列表

這是G1垃圾收集器開關的完整列表。記住使用上面列出的最佳實踐。

Option and Default ValueDescription
-XX:+UseG1GC使用垃圾優先(G1)收集器
-XX:MaxGCPauseMillis=n設定最大GC暫停時間的目標。這是一個軟目標,JVM將盡力實現它。
-XX:InitiatingHeapOccupancyPercent=n啟動併發GC迴圈的(整個)堆佔用率的百分比。它不是基於GCs的一個併發迴圈,而是基於GCs的一個併發迴圈。值為0表示“do constant GC cycles”。預設值為45。
-XX:NewRatio=n新老年代規模之比。預設值為2。
-XX:SurvivorRatio=n伊甸園/倖存者空間大小的比率。預設值為8。
-XX:MaxTenuringThreshold=n保持閾值的最大值。預設值為15。
-XX:ParallelGCThreads=n在並行階段中使用的垃圾收集器的執行緒數。預設值隨執行JVM的平臺而異。
-XX:ConcGCThreads=n併發垃圾回收器將使用的執行緒數。預設值隨執行JVM的平臺而異。
-XX:G1ReservePercent=n設定保留為假上限的堆數量,以減少升級失敗的可能性。預設值為10。
-XX:G1HeapRegionSize=n使用G1,Java堆被細分為大小一致的區域。這將設定各個子分割槽的大小。此引數的預設值根據堆大小根據人體工程學確定。最小值為1Mb,最大值為32Mb。

關於G1的垃圾回收器的日誌記錄

關於G1的垃圾回收器的日誌記錄

我們需要討論的最後一個主題是使用日誌資訊來分析G1收集器的效能。本節簡要介紹了用於收集資料和列印在日誌中的資訊的控制開關選項。

設定詳細的日誌記錄

可以將詳圖設定為三個不同的詳細程度。

(1) -verbosegc (相當於 -XX:+PrintGC) 將日誌的詳細級別設定為fine.

簡單的輸出

[GC pause (G1 Humongous Allocation) (young) (initial-mark) 24M- >21M(64M), 0.2349730 secs]
[GC pause (G1 Evacuation Pause) (mixed) 66M->21M(236M), 0.1625268 secs]    

(2) -XX:+PrintGCDetails 將詳細程度設定為精細。選項顯示以下資訊:

  • 將顯示每個階段的平均時間、最小時間和最大時間。
  • 根掃描、資源集更新(使用已處理的緩衝區資訊)、資源集掃描、物件複製、終止(具有嘗試次數)。
  • 還顯示了“其他”時間,例如選擇CSet、參考處理、參考排隊和釋放CSet所花費的時間。
  • 顯示了伊甸園、倖存者和總堆佔用率。

簡單輸出

[Ext Root Scanning (ms): Avg: 1.7 Min: 0.0 Max: 3.7 Diff: 3.7]
[Eden: 818M(818M)->0B(714M) Survivors: 0B->104M Heap: 836M(4096M)->409M(4096M)]

(3) -XX:+UnlockExperimentalVMOptions -XX:G1LogLevel=finest 將詳細程度設定為“最精細”。與finer類似,但包含單個工作執行緒資訊。

[Ext Root Scanning (ms): 2.1 2.4 2.0 0.0
           Avg: 1.6 Min: 0.0 Max: 2.4 Diff: 2.3]
       [Update RS (ms):  0.4  0.2  0.4  0.0
           Avg: 0.2 Min: 0.0 Max: 0.4 Diff: 0.4]
           [Processed Buffers : 5 1 10 0
           Sum: 16, Avg: 4, Min: 0, Max: 10, Diff: 10]

確定時間

幾個開關決定了時間在GC日誌中的顯示方式。

(1) -XX:+PrintGCTimeStamps - 顯示自JVM啟動以來經過的時間。

Sample Output

1.729: [GC pause (young) 46M->35M(1332M), 0.0310029 secs]

(2) -XX:+PrintGCDateStamps - 為每個條目新增時間字首。

2012-05-02T11:16:32.057+0200: [GC pause (young) 46M->35M(1332M), 0.0317225 secs]

瞭解G1日誌

為了理解日誌,本節使用實際的GC日誌輸出定義了許多術語。以下示例顯示了日誌的輸出,並解釋了將在其中找到的術語和值。

Note: 更多資訊請檢視 Poonam Bajaj’s Blog post on G1 GC logs.

G1日誌術語索引

Clear CT
CSet
External Root Scanning
Free CSet
GC Worker End
GC Worker Other
Object Copy
Other
Parallel Time
Ref Eng
Ref Proc
Scanning Remembered Sets
Termination Time
Update Remembered Set
Worker Start

並行時間

414.557: [GC pause (young), 0.03039600 secs] [Parallel Time: 22.9 ms]
[GC Worker Start (ms): 7096.0 7096.0 7096.1 7096.1 706.1 7096.1 7096.1 7096.1 7096.2 7096.2 7096.2 7096.2
       Avg: 7096.1, Min: 7096.0, Max: 7096.2, Diff: 0.2]

Parallel Time – 暫停的主要並行部分的總執行時間
Worker Start –工作開始的時間戳t

Note: 日誌按執行緒id排序,並且在每個條目上都是一致的

外部根掃描

[Ext Root Scanning (ms): 3.1 3.4 3.4 3.0 4.2 2.0 3.6 3.2 3.4 7.7 3.7 4.4
     Avg: 3.8, Min: 2.0, Max: 7.7, Diff: 5.7]

External root scanning - 掃描外部根所花費的時間(例如,指向堆的系統字典之類的東西.)

更新記憶集

[Update RS (ms): 0.1 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 Avg: 0.0, Min: 0.0, Max: 0.1, Diff: 0.1]
[Processed Buffers : 26 0 0 0 0 0 0 0 0 0 0 0
    Sum: 26, Avg: 2, Min: 0, Max: 26, Diff: 26]

Update Remembered Set - 必須更新已完成但尚未在暫停開始之前由併發優化執行緒處理的任何緩衝區。時間取決於卡片的密度。卡片越多,花的時間就越長。

掃描記憶集

[Scan RS (ms): 0.4 0.2 0.1 0.3 0.0 0.0 0.1 0.2 0.0 0.1 0.0 0.0 Avg: 0.1, Min: 0.0, Max: 0.4, Diff: 0.3]F

Scanning Remembered Sets - 查詢指向集合集中的指標。

物件複製

[Object Copy (ms): 16.7 16.7 16.7 16.9 16.0 18.1 16.5 16.8 16.7 12.3 16.4 15.7 Avg: 16.3, Min: 12.3, Max:  18.1, Diff: 5.8]

Object copy – 每個執行緒花費在複製和疏散物件上的時間。

終止時間

[Termination (ms): 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
0.0 Avg: 0.0, Min: 0.0, Max: 0.0, Diff: 0.0] [Termination Attempts : 1 1 1 1 1 1 1 1 1 1 1 1 Sum: 12, Avg: 1, Min: 1, Max: 1, Diff: 0]

Termination time - 當一個工作執行緒完成了要複製和掃描的特定物件集時,它將進入終止協議。它尋找要竊取的工作,一旦完成,它將再次進入終止協議。終止嘗試計算所有竊取工作的嘗試。

GC工作執行緒結束

[GC Worker End (ms): 7116.4 7116.3 7116.4 7116.3 7116.4 7116.3 7116.4 7116.4 7116.4 7116.4 7116.3 7116.3
    Avg: 7116.4, Min: 7116.3, Max: 7116.4, Diff:   0.1]
[GC Worker (ms): 20.4 20.3 20.3 20.2 20.3 20.2 20.2 20.2 20.3 20.2 20.1 20.1
     Avg: 20.2, Min: 20.1, Max: 20.4, Diff: 0.3]

GC worker end time – 單個GC工作程式停止時的時間戳。

GC worker time – 單個GC工作執行緒所用的時間。

其他GC工作

[GC Worker Other (ms): 2.6 2.6 2.7 2.7 2.7 2.7 2.7 2.8 2.8 2.8 2.8 2.8
    Avg: 2.7, Min: 2.6, Max: 2.8, Diff: 0.2]

GC worker other – 不能歸屬於前面列出的輔助階段的時間(對於每個GC執行緒)。應該很低。在過去,我們看到過過高的值,這些值被歸因於JVM其他部分的瓶頸(例如,分層的程式碼快取佔用率的增加)。

清除 CT**

[Clear CT: 0.6 ms]

清除資源集掃描後設資料的卡片表所用的時間

其他

[Other: 6.8 ms]

GC暫停的其他連續階段所用的時間。

CSet

[Choose CSet: 0.1 ms]

完成要收集的區域集所用的時間。通常很小;當必須選擇舊的時稍長一些。

Ref Proc

[Ref Proc: 4.4 ms]

處理軟、弱等引用所花費的時間,這些引用是從GC的前幾個階段延遲的。

Ref Enq

[Ref Enq: 0.1 ms]

將軟引用、弱引用等放到掛起列表上所花費的時間。

Free CSet

[Free CSet: 2.0 ms]

釋放剛剛收集到的區域集(包括它們的記憶集)所花費的時間。

綜述

在本文中,您已經獲得了javajvm中包含的G1垃圾收集器的概述。首先,您瞭解了堆和垃圾收集器是任何javajvm的關鍵部分。接下來,您回顧瞭如何使用CMS收集器和G1收集器進行垃圾收集。接下來,您瞭解了G1命令列開關以及使用它們的最佳實踐。最後,您瞭解了記錄GC日誌中包含的物件和資料。

在本教程中,您學習了:

  • Java JVM的元件
  • G1收集器概述
  • CMS收集器綜述
  • G1收集器綜述
  • 命令列開關和最佳實踐
  • 關於G1的日誌記錄

資源

欲瞭解更多資訊和相關資訊,請訪問這些網站和連結。

Credits

  • Curriculum Developer: Michael J Williams
  • QA: Krishnanjani Chitta