Getting Started with the G1 Garbage Collector(譯)

原文連接:Getting Started with the G1 Garbage Collectorhtml

概述

目的

這篇教程包含了G1垃圾收集器使用和它如何與HotSpot JVM配合使用的基本知識。你將會學到G1收集器內部是如何運做的,切換到使用G1的命令和記錄其操做的日誌選項。java

完成時間

大概一個小時(我操,一個小時我勉強能夠看完,要是這樣邊翻譯邊看仍是須要點時間的呀git

簡介

這個OBE(我不知道OBE是什麼意思)包含了Java中Java虛擬機(JVM)G1垃圾收集(GC)的基本知識。在這個OBE的第一部分,在介紹垃圾收集的同時也介紹了一下JVM。接下來,將帶大家一塊兒回顧一下CMS收集器如何與Hotspot協同工做的。而後,就是一步一步的引導你們學習當G1垃圾收集器搭配Hotspot的時候,JVM中的垃圾收集器是如何工做的。在這以後,將會有一部分講解G1垃圾收集器的垃圾收集的命令行選項。最後你將會學習使用G1收集器時的垃圾收集日誌選項。web

硬件和軟件要求

下面列舉了硬件和軟件的要求:算法

  • 運行Windows XP及後來版本,Mac OS或者Linux的PC。注意目前只在Windows 7上親自測試過,而不是在因此的平臺上都測試過。可是,在OS X或者Linux上一切都運行良好。同時,若是你的機器是多核的就更好了。
  • Java 7 Update 9或者之後的版本
  • 最新的Java 7演示和樣例Zip壓縮文件

前提

在開始本教程以前,你應該:數據庫

若是你尚未安裝JDK的話,請先下載並安裝最新版本的Java JDK(JDK 7u9或者以後版本)。
Java 7 JDK 下載編程

以及從相同地方下載樣例壓縮文件。解壓並將其放到目錄總。好比:C:\javademos瀏覽器

Java概述(如下都是廢話。。。)

來不想翻譯的,算了,仍是慢慢翻吧安全

Java是Sun Microsystems公司於1955年發佈的一門變成語言以及計算平臺。它是支撐包括由Java編寫的utilities,遊戲和商務應用等程序的底層技術。Java運行在世界範圍內超過8億5千萬臺PC上以及數十億的設備中,包括移動設備和TV。Java由一系列關鍵組件組成,而且他們做爲一個總體,構成了Java平臺。服務器

Java運行時版本

當你下載了Java以後,你就得到了Java運行時環境(JRE)。JRE包括Java虛擬機(JVM),Java平臺核心類,和支撐Java平臺的庫。以上3個都是在你的電腦上運行Java程序必不可少的。在Java 7中,Java程序能夠做爲操做系統的桌面應用運行,用Java Web Start能夠從Web上安裝並做爲桌面應用運行,或者在瀏覽器中(使用JavaFX)做爲Web嵌入程序運行。

Java編程語言

Java是一門面向對象的變成語言,它有以下特性。

  • 平臺無關性- Java應用被編譯成字節碼,這些字節碼存儲在類文件中並加載到JVM中。因爲應用是在JVM中運行的,因此它們能夠在不一樣的系統和設備中運行。
  • 面向對象 - Java是一門面向對象的語言,從C和C++中吸收了不少特性並加以改進。
  • 自動垃圾收集 - Java能夠自動分配和回收內存,因此應用程序不用受內存分配和回收等困擾。
  • 豐富的標準庫 - Java包括了不少預約義的對象,這些對象能夠很方便的完成輸入/輸出,網絡通訊以及其餘數據處理的任務。

Java開發套件

Java Development Kit(JDK)是一套用於開發Java應用的工具。有了JDK,你能夠編譯Java語言編寫的程序,而且在JVM上運行它們。除此以外,JDK也提供了一套用於打包和發佈你的應用的工具。JDK和JRE共享Java應用程序接口(Java API)。Java API是預打包的庫的集合,開發者能夠利用Java API來開發他們的應用程序。有了Java API來完成許多開發中共同的任務使得開發過程更方便,好比字符串處理,日期/時間的處理,網絡通訊和數據結構的實現(好比鏈表,映射,棧和隊列等)。(tmd,翻譯的好累。。。

Java虛擬機(Java Virtual Machine)

Java虛擬機是一種抽象的計算機器。JVM是一個程序,可是對於那些在它上面運行的程序而言,它像是一個機器。這樣一來,Java程序都是用同一套接口和庫來編寫的。每一個在特定平臺上面實現的Java虛擬機,都會把Java編程指令翻譯成運行在本地操做系統上的指令和命令。如此,Java程序可以得到平臺無關性。

 

JVM第一個實現的原型是由Sun Microsystems公司完成的,在相似於Personal Digital Assistant(PDA)的手持設備上模擬運行Java虛擬機指令。 Oracle's current implementations emulate the Java virtual machine on mobile, desktop and server devices, but the Java virtual machine does not assume any particular implementation technology, host hardware, or host operating system. It is not inherently interpreted, but can just as well be implemented by compiling its instruction set to that of a silicon CPU. It may also be implemented in microcode or directly in silicon.

 

Java虛擬機其實並不知道什麼是Java編程語言,它僅僅知道一種特殊的二進制格式,即類文件格式。一個類文件中包含了Java虛擬機指令(字節碼)和符號表,以及其餘的一些輔助信息。

 

爲了安全起見,Java虛擬機對類文件中的代碼施加了嚴格的句法和結構的限制。然而,任何可以表達成有效類文件的變成語言均可以在Java虛擬機中運行。因爲平臺無關性以及普遍可用性,其餘語言的實現者也能夠將起放到Java虛擬機中運行。(1) The Java Virtual Machine

探索JVM的架構

Hotspot架構

HotSpot JVM的架構能夠有力的支持高性能和大規模的可擴展性的特徵和能力。例如,HotSpot JVM JIT編譯器可以生成動態優化的代碼。換句話說,它們在Java程序運行的時候能夠進行優化決策,而且對於底層系統架構來講能夠生成高質量的本地機器碼。除此以外,經過成熟的改進以及連續的運行環境工程化和多線程的垃圾收集器,HotSpot JVM甚至在最大型的計算機中均可以得到高可擴展性。

 

image

圖1 JVM的主要組件包括類加載器,運行時數據區域,和執行引擎。

 

Hotspot中的關鍵組件

下圖中描述了JVM中和性能密切相關的組件。

 

image

圖2 JVM中和性能密切相關的組件

 

在進行性能調優的時候,JVM中有3個組件須要關注。Java堆是你的對象數據存儲的地方。這塊區域是由Java虛擬機開啓時所選擇的垃圾收集器來管理的。大多數的調優選項都是根據你的應用場景設置合適的堆尺寸以及選擇最合適的垃圾收集器。JIT編譯器對於性能也有很大的影響,可是對於新版本的JVM來講,這個已經不多須要調整了。

性能指標

通常來講,當對一個Java應用程序調優的時候,關注的焦點一般是響應或者吞吐量這兩者之一。在本教程的後面會回過頭來再看這兩個概念。

響應速度

響應速度指的是一個應用或者系統對請求過來以後反應的快慢。典型的例子有:

桌面UI對事件的反應快慢

一個網站返回頁面速度有多快

一個數據庫查詢返回數據有多快

對於講求響應速度的應用來講,長時間的暫停是不可接受的。因此須要在短期內就能夠響應。

吞吐量

吞吐量關注的是使一個應用在特定的時間內完成最大的工做量。衡量吞吐量的例子有如下幾種:

在給定時間內完成的事務。

一個小時內一個批處理程序能夠完成的工做量。

在一個小時內一個數據庫能夠完成的查詢數量。

對於吞吐量來講,能夠忍受長時間的暫停。因爲高吞吐量的任務關注的是以長時間的基準,快速響應時間並不在考量的範圍以內。

G1垃圾收集器

G1垃圾收集器是一款適用於服務器的垃圾收集器,這些服務器通常有多個處理器以及很大的內存。它可以很好的知足high probability同時又能達到很高的吞吐量。Oracle JDK7 update 4以及後來版本都徹底支持G1垃圾收集器。G1垃圾收集器專爲如下應用設計的:

可以像CMS收集器同樣和應用線程一塊兒併發操做。

可以壓縮可用空間,而不會出現因垃圾收集致使的漫長的暫停時間。

須要更多可預測的GC暫停時間。

不想犧牲不少的吞吐量性能。

不須要過多的Java堆。

 

G1計劃做爲Concurrent Mark-Sweep(CMS)垃圾收集的長期替代。和CMS相比較,G1有不少不一樣之處使得G1比CMS更好。其中的一個特色是,G1是一個帶壓縮的垃圾收集器。G1可以充分的壓縮可用內存來避免出現使用細粒度的可用空間列表進行內存分配,而是依賴於區域。這極大地簡化了垃圾收集的一部分工做,最大程度地減小了可能存在的碎片化問題。同時,G1比CMS提供了更多的可預測的垃圾收集暫停,而且容許用戶指定想要的暫停目標。(感受挺牛逼的啊

G1 Operational Overview(這個Operational怎麼翻譯。。。。)

 

之前的垃圾收集器(serial,parallel,CMS)都將堆分爲如下3個部分:年輕代,老年代,和固定內存大小的永久代。

 

 

image

圖3 之前的垃圾收集器對堆的劃分

全部的內存中的對象最終都會落到這3個區域的其中一個。可是,G1收集器採用了一種不一樣的方式。

 

image

圖4 G1垃圾收集器對堆的劃分

 

堆被劃分爲同等大小的堆區域的集合,每一塊在虛擬內存中都的地址都是相接的。(這句話的意思是在虛擬內存中你能夠想象這些塊都是放在一塊兒的,可是在實際的物理內存中它們可能相隔n遠)某些區域的集合被分配相同的角色(好比eden,survivor,old),就像在之前的垃圾收集器中那樣,可是它們並無固定的大小。這在內存的使用上提供了極大的彈性。

 

在進行垃圾回收的時候,G1的操做方式相似於CMS收集器。G1進行併發的全局標記階段來決定整個堆中對象是否存活。在標記階段完成以後,G1會知道哪些區域的大部分是空的。它會先收集這些區域,從而會有大量的空閒空間。這就是爲何這種垃圾收集方法叫作Garbage-First(同志們,這就是爲啥它叫G1啊)。正如它的名字所暗示的那樣,G1將它的收集和壓縮活動集中在那些儘量裝滿可回收對象的區域,即,垃圾。G1使用暫停預測模型來知足用足自定義的暫停時間目標,根據特定的暫停時間目標來選擇準備回收區域的數量。(有點好奇它的暫停預測模式是怎麼構建的?

 

被G1識別爲到已經達到可回收時機的區域將會將會用撤走(離場?evacuation)的方法進行回收。G1會將堆中一個或者多個區域中的對象複製到堆中的一個單一的區域,在這個過程當中會同時對內存進行壓縮和釋放。這種evacuation的動做在多處理器的CPU上是併發進行,這樣能夠減小暫停時間並提升吞吐量。如此,每一次垃圾回收時,G1都會在用戶自定義的暫停時間中持續工做並減小內存的碎片化。這種能力超過了以往的任何方法。CMS(Concurrent Mark Sweep)垃圾收集器不會對內存進行壓縮。ParallelOld垃圾收集器只會對整個堆進行壓縮,所以致使了至關長時間的暫停。

 

必需要注意到G1並非一個實時的垃圾收集器。它會以很高的可能性來知足設定的暫停時間目標,但這並非必定的。根據以前的垃圾收集數據,G1會對用戶自定的目標時間內可能進行回收的區域個數進行估算。所以,G1收集器對收集的區域會有一個合理準確的模型,而後它利用這種模型來決定在暫停時間內回收哪些以及有多少區域會被回收。

 

注意:G1既有併發(和應用線程一塊兒執行,好比refinement,標記和清理)階段也有並行階段(多線程,好比stop-the-world)。Full GC仍然是單線程的,若是調優得當的話,你的應用應該能夠避免full GC。

G1空間佔用(Footprint)

若是你從ParallelOldGC或者CMS收集器轉而使用G1,你頗有可能發現JVM進行佔用的空間更大了。這其中大部分和"審計"數據結構有關,好比Rembered Sets和Collection Sets。

Remembered Sets或者RSets記錄那些到一個給定的區域中對象的引用。在堆上每一個區域都有一個RSet。RSet使得一個區域的並行和獨立收集變得可能。RSets對真個空間佔用的影響小於5%。

Collection Sets又或者叫CSets是那些將會在下一次GC中被回收的區域集合。全部在CSet中存活的對象都會在下一次GC是被evacuated(copied/moved)。這些區域的集合能是Eden,survivor或者老年代。CSets對JVM佔用內存的影響小於1%。

建議使用G1垃圾收集器的場景

G1第一個關注點是爲用戶運行的那些須要很大的堆內存又要短的GC延遲提供一種解決方案。這意味着堆的大小在6GB或者更大時,穩定的可預測的暫停時間將小於0.5秒。

對於目前使用CMS或者ParallelOldGC垃圾收集器的應用,若是具備如下一個或者超過一個特徵的,換成G1收集器將會對性能有很大提高。

  • Full GC停留的時間太長或者太頻繁。
  • 新對象分配的速率或者對象老化的速率隨時間變化很大。
  • 比預期長得多的垃圾收集時間或者壓縮暫停的時間(比0.5到1秒還久)。

注意:若是你正在使用CMS或者ParallelOldGC而且你的應用並無受長時間的垃圾收集暫停時間之苦,那麼最好仍是保持使用你當前的垃圾收集器。對於使用最新的JDK而言,切換到G1並非必須的。

回顧CMS中的垃圾收集

回顧通常的垃圾收集以及CMS

 

併發標記清除(Concurrent Mark Sweep)收集器(又稱爲concurrent low pause collector)收集老年代。它試圖經過和應用線程併發工做時最大程度地完成垃圾收集任務來最小化暫停時間。一般CMS不會複製或者壓縮存活的對象。這種垃圾收集方式不會移動存活的對象。若是碎片化致使問題了,那麼採用的方法就是分配一個更大的堆。

注意:CMS收集器使用和並行收集器同樣的算法來回收年輕代。

CMS垃圾收集的過程

 

CMS經過如下階段來完成對堆中老年代的收集工做:

 

 

Phase

Description

(1)初始標記
(Stop the World事件)
在老年代的對象被標記爲可達,其中包括那些從年輕代可達的對象。相對於minor GC的暫停時間,初始標記致使的暫停時間很短。
(2)併發標記 在Java應用線程運行的同時遍歷老年代中可達的對象。從已被標記的對象開始,而且從根節點依次遍歷可達的對象。mutators從併發階段2,3和5開始執行而且任何在CMS階段分配的對象(包括被promotion的對象)都當即被標記爲存活。
(3)從新標記
(Stop the World事件)
找到那些在併發標記階段在併發標記收集器完成跟蹤以後因爲Java應用線程更新致使錯過的對象。
(4)併發清除 收集那些在標記階段標記爲不可達的對象。死亡對象的收集增長了能夠用後面分配的空閒列表的空間。死亡對象的Coalescing可能發生在這個階段。注意存活的對象並無移走。
(5)從新設定 經過清理數據結構準備下一次的併發收集。

 

回顧垃圾收集的步驟

接下來,讓咱們回顧一下CMS垃圾收集器是怎麼一步一步進行垃圾收集的。

Next, let's review CMS Collector operations step by step.

1. CMS垃圾收集器中的堆結構

堆被分紅了3個空間。

 

image

圖5 CMS中的堆劃分

 

年輕代被分紅了1個Eden空間和2個survivor空間。老年代連續的空間(contiguous)。

2. CMS中的年輕代GC是如何進行的?

在下圖中年輕代用綠色標註了,而老年代則是藍色的。若是你的程序運行了一下子的話,你的Java堆可能就長成如今這樣。對象分散在老年代中。

 

image

圖6 CMS中對象的分佈

在CMS中,老年代中的對象都是原位回收的。它們不會被處處移動。只有在執行Full GC的時候,老年代的空間纔會被壓縮。

 

3. 年輕代的收集

 

存活的對象都從Eden空間和Survivor空間複製到另外一個Survivior空間中。任何到達了年齡閾值的對象都會提高到老年代中。

image

圖7 年輕代的收集

 

4. 年輕代收集以後

 

image

圖8 年輕代收集以後

 

新提高到老年代的中的對象在圖8中都用深藍色標註。綠色的對象都是未被提高到老年代的年輕代中存活下來的對象。

 

5. CMS中老年代的收集

兩個stop-the-world的事件會發生:初始標記和從新標記。當老年代到達了必定的佔用率以後,CMS收集便拉開了序幕(kicked off)。

 

image

圖9 CMS中老年代的收集

 

(1)初始標記中存活的(可到達的)對象會被標記,這是一個短暫停的過程。

(2)併發標記在應用線程執行的同時找到存活的線程。

最後在(3)從新標記階段,會找到以前(2)中併發標記中被錯過的對象。

 

6. 老年代的收集 - 併發清除

 

在以前階段中沒有被標記的對象都會被回收。但並不會對標記的對象壓縮。

 

image

圖10 老年代的收集 - 併發清除

 

注意:未被標記的對象 == 死亡對象

 

7. 老年代的收集 - 清除以後

 

在(4)清除階段以後,你能夠發現,不少的內存都被釋放掉了。同時也會發現沒有進行壓縮過程。

 

image

圖11 老年代的收集 - 清除以後

 

最後,CMS收集器會到(5)階段,即重置階段並等待下一次GC的到來。(GC。。。我不純潔了)

 

G1垃圾收集器詳細介紹

G1垃圾收集器詳細介紹

G1垃圾收集器採用不一樣的方式來對堆進行分配。下面的圖片一步一步回顧了G1系統。

1. G1堆結構

堆內存被劃分爲相同大小的固定區域。

 

image

 

在啓動的時候JVM會選擇區域的大小。JVM一般會將堆分爲2000個區域,每一個區域大小大概爲1到32Mb之間。

 

G1堆的劃分

實際上,這些區域被映射到邏輯上的Eden,Survivor和Old Generation Space。

 

image

 

圖中不一樣的顏色表明了每塊區域對應的角色。存活的對象被evacuated從一個區域到另外一區域。區域的回收被設計爲並行模式,既能夠和應用線程共存,也能夠和stop-the-world。正如鎖演示的那樣,這些區域能夠被分配到Eden,survivor和old generation。除此以外,還有被被稱之爲Humongous區域的第4種類型的區域。這些區域使用來容納那些佔標準區域大小50%甚至以上的對象的。它們存儲時做爲相鄰的區域。最終最後這種類型的區域是堆中未使用的區域。

注意:在這篇教程寫的時候,對humongous對象的回收並無進行優化。所以,你須要避免建立這類型的對象。

 

G1中的年輕代

整個堆大約被分爲2000個區域。最小的區域是1Mb,最大的區域是32Mb。藍色的區域持有老年代對象而綠色的區域則是持有年輕代對象。

 

image

 

注意,這些區域並不像之前的垃圾收集器中那樣須要相鄰。

G1中的一次年輕代收集

存活的對象會別evacuated到一個或則更多的survivor區域中。若是達到了老化閾值,某些對象會被提高到老年代的區域中。

 

image

 

這是一次Stop-The-World的暫停。Eden的大小和Survivor的大小會被計算出來爲下一次年輕代的GC作準備。會保持審計信息來幫忙計算大小。同時也考慮到暫停時間之類的目標。這種方式使得很是容易地從新調整區域的大小,只要須要,能夠隨時的擴大或者縮小。

G1中年輕代收集結束時

存活的對象被evacuated到survivor區域或者老年代中。

 

image

 

最近提高的對象用深藍色表示。Survivor區域則用綠色表示。

用一下的話來總結一下G1中年輕代的收集:

  • Java堆是被分爲不少區域的單塊內存空間。
  • 年輕代的內存由一系列不連續的空間組成。
  • 年輕代的收集是會致使Stop-The-World的。全部的應用線程在這個過程當中會中止。
  • 年輕代的收集是多線程並行進行的。
  • 存活的對象都被複制到新的survivor或者老年代區域中。

Old Generation Collection with G1

就像CMS收集器同樣,G1收集器被設計爲對於老年代對象的收集低暫停時間。小表中描述了G1收集器中老年代的G1收集階段。

 

G1收集階段 - 併發標記Cycle階段

G1收集器會對堆中的老年代執行如下階段。要注意其中某些階段是在年輕代收集中的。

 

階段

描述

(1)初始標記(Stop-The-World) 這是一個會Stop-The-World的事件。在G1中,這個階段是藉助(piggyback)於一次正常的年輕代GC的。標記survivor(root regions)中有引用到老年代中的對象。
(2)Root Region掃描 掃描survivor區域中那些會進入老年代的引用。當程序恢復運行的時候會進行。這個階段必需要在年輕代垃圾收集以前完成。
(3)併發標記 找到整個堆上存活的對象。這個在應用運行的時候發生。這個階段能夠被年輕代的垃圾收集打斷。
(4)從新標記階段(Stop-The-Word) 完成堆上存活對象的標記。使用被稱之爲snapshot-at-the-beginning(SATB)的算法,這要比CMS收集器中的算法快得多。
(5)清理(Stop-The-World和併發)
  • 執行對存活對象的審計並完成空閒區域的釋放。(Stop-The-World)
  • Scrubs Remembered Sets。(Stop-The-World)
  • 重置空閒的區域並將它們返回到空閒列表。(Concurrent)
(*)複製(Stop-The-World) 將存活的對象evacuate或者copy到新的未使用的區域中都是Stop-The-World的暫停。這些和年輕代區域時候完成,在日誌中輸出爲[GC pause (young)]。或者在年輕代區域和老年代區域中同時發生,日誌爲[GC Pause (mixed)]。

 

定義了以上的階段以後,咱們來看一下這些階段如何與G1收集器中的老年代交互的。

 

6. 初始標記階段

存活對象的初始標記是附着於年輕代的垃圾收集的。在日誌中的輸出是標爲GC pause (young)(initial-mark)。

 

image

 

7. 併發標記階段

若是有空的區域被找到(用"X"表示的),它們立刻會在從新標記階段被清除掉。一樣,決定是否存活的審計信息也會被計算出來。

 

image

 

8. Remark Phase

空的區域會被移走和收回。並且全部區域的是否存活都計算出來了。

 

image

 

9. 複製/清理階段

G1選擇那些具備最低"存活性"的區域,這些區域可以以最快的速度收集。而後這些區域會在和年輕代GC相同的時間被回收。這日誌中的輸出是[GC pause (mixed)]。所以,年輕代和老年代的回收都是在同一時間。

 

image

 

10. 複製/清理以後的階段

選擇的區域被回收並被壓縮到深藍色的區域中,深藍色的區域在下圖中顯示了。

 

image

 

老年代中GC的總結

 

這裏有些關鍵的地方要對老年代進行總結一下:

  • 併發標記階段:存活性的信息會在應用程序運行的時候同時進行。存活信息代表了那些在evacuation階段最適宜被收回的區域。這裏沒有像CMS中那樣的Sweeping階段。
  • 從新標記階段:使用Snapshot-at-the-Beginning算法,要比CMS中的算法更快。徹底爲空的區域會被回收。
  • 複製/清理階段:年輕代和老年代會在同一時刻被回收。老年代區域的選擇是基於它們的存活性的。

命令行選項和最佳實踐

 

這一部分咱們來看一下G1中的命令行選項。

基礎的命令行

爲了激活G1垃圾收集器,可使用: -XX:+UseG1GC

這裏有一個啓動Java2Demo,這個例子包含在JDK的demos中

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:InitatingHeapOccupancyPercent=45 當堆的空間佔用達到這麼多以後會啓動一個併發的垃圾收集週期。G1中正是使用的這種整個對的佔用,而不是某個代中的佔用。若是設置爲0就表示"進行constant垃圾收集週期"。這個選項的默認值是45(也就是對的佔用達到了45%)。

 

最佳實踐

這裏提供了一些你在使用G1垃圾收集器時應該遵循的一些最佳實踐。

 

不要設置年輕代的大小

 

經過-Xmn來顯式地設置年輕代的大小會干預(meddles)到CG1收集器的默認行爲。

  • G1將不會再遵循收集時的暫停時間目標。因此大致上(in essence),設置了年輕代的大小會禁用掉暫停時間目標。
  • G1將不能隨着須要而擴大或者收縮年輕代空間的大小。因爲大小被固定了,對於其大小不會由任何改變。

 

響應時間度量

設置XX:MaxGCPauseMillis=<N>,而不是使用平均響應時間(ART),是的知足目標的機率達到90%或者更多。這意味着90%的用戶發出請求時將不會超過預設的時間目標。記住,暫停時間是一個目標,而不是必須知足的一個條件。

 

Evacuation Failure會怎麼樣?

 

爲了survivors或者提高年輕代而進行GC是,會由於JVM用光了java堆而致使promotion failure。堆因爲已經達到了最大的尺寸而不能繼續擴展。這在用-XX:+PrintGCDetails時會to-space overflow而顯示。這將致使花費增長。

 

GC會繼續進行使得空間必須被釋放。

複製失敗的對象將必須提高到老年代中。

任何在CSets中的RSets的更新將從新生成。

全部以上的步驟的花費都很是大。

 

若是避免Evacuation Failure

 

爲了不Evacuation Failure,考慮一下選項。

增長堆的大小:增長-XX:G1ReservePercent=n,默認的值是10。G1會建立一個false ceiling經過試圖使reserve memory空間以免須要更多的"to-space"。

更早地開始標記週期。

使用-XX:ConcGCThreads=n選項來增長標記線程。

 

完整的G1垃圾收集的選項

 

一下是完整的G1收集選項,記得使用上面的最佳實踐哦。

選項及其默認值 描述
-XX:+UseG1GC 使用G1垃圾收集器
-XX:MaxGCPauseMillis=n 設置最大的暫停時間目標。這是一個軟性的目標,而且JVM會努力達到這個目標。
-XX:InitiatingHeapOccupancyPercent=n 啓動併發GC的堆內存使用的百分比。這個選項被GC用來根據整個Heap佔用百分比來觸發一次併發的垃圾收集週期,而不是由於某一代的佔用率。若是這個值爲0,表示進行"do constant GC週期"。默認值是45。
-XX:NewRatio=n 新/老代的大小之比,默認是2。
-XX:SurvivorRatio=n eden/survivor空間的比,默認值是8。
-XX:MaxTenuringThreshold=n 最大的老化閾值,這個默認值是15。
-XX:ParallelGCThreads=n 設置垃圾收集並行階段的線程數量。默認的值隨着JVM運行的平臺不一樣而不一樣的。
-XX:ConcGCThread=n 垃圾收集在並行階段所使用的線程數。默認的值隨着JVM運行的平臺不一樣而不一樣的。
-XX:G1ReservePercent=n 爲了減小promotion失敗可能性而設置的heap的保留的false ceiling。默認值是10。
-XX:G1HeapRegionSize=n 在G1中,Java堆被分爲同一大小的區域。這個選項設定了區域的大小。這個值是根據所分配的堆的大小不一樣而不一樣的。最小值爲1Mb,最大值爲32Mb。

 

G1中的GC日誌

咱們要講的最後一個主題是用來分析G1垃圾收集器的日誌信息。這個部分提供你能使用收集信息和垃圾收集日誌中打印的信息的選項。

 

設置日誌細節

你能夠設置3中不一樣垃圾收集的日誌級別。

(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設置了日誌界別爲finer。這個選項提供了一下信息:

  • 每一個階段的平均,最小和最大時間
  • Root Scan,RSet更新(已經處理的buffer信息),RSet Scan,對象複製,終結(嘗試的次數)。
  • 同時也顯示了其餘時間好比選擇CSet花費的時間,引用處理,引用入列和釋放CSet。
  • 顯示Eden,Survivor和整個堆的佔用。

 

輸出樣例

 

[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 設置細節級別爲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]

Determing Time

有一些開關使用來調整GC日誌中的時間如何顯示的。

(1)-XX:+PrintGCTimeStamps 顯示JVM啓動以後的通過的時間。

樣例輸出

 

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]

 

理解GC日誌

爲了理解日誌,這個部分定義了一些在GC輸入的日誌中所用的術語。一下輸出顯示了一些GC日誌中擴展的術語。

 

注意:若是須要更多的信息,請訪問Poonam Bajaj's Blog post on G1 GC logs

 

GC日誌術語索引

 

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

 

Parallel Time

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 – 垃圾線程開始的時間戳
Note: The logs are ordered on thread id and are consistent on each entry

注意:這個日誌是按照線程id來排序的,而且每一條日誌都是一致的。

 

External Root Scanning

[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 - 用於掃描外部的根對象花的時間(好比,像執行堆的system dictionary)

 

Update Remembered Set

[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 - 已經完成的可是尚未被concurrent refinement線程處理的緩衝。Time depends on density of the cards. The more cards, the longer it will take.

 

Scanning Remembered Sets

[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 - Look for pointers that point into the Collection Set.

 

Object Copy

[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 – The time that each individual thread spent copying and evacuating objects.

 

Termination Time

[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 - When a worker thread is finished with its particular set of objects to copy and scan, it enters the termination protocol. It looks for work to steal and once it's done with that work it again enters the termination protocol. Termination attempt counts all the attempts to steal work.

 

GC Worker End

[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 – Timestamp when the individual GC worker stops.

GC worker time – Time taken by individual GC worker thread.

 

GC Worker Other

[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 – The time (for each GC thread) that can't be attributed to the worker phases listed previously. Should be quite low. In the past, we have seen excessively high values and they have been attributed to bottlenecks in other parts of the JVM (e.g., increases in the Code Cache occupancy with Tiered).

 

Clear CT

[Clear CT: 0.6 ms]
Time taken to clear the card table of RSet scanning meta-data

 

Other

[Other: 6.8 ms]
Time taken for various other sequential phases of the GC pause.

 

CSet

[Choose CSet: 0.1 ms]
Time taken finalizing the set of regions to collect. Usually very small; slightly longer when having to select old.

 

Ref Proc

[Ref Proc: 4.4 ms]
Time spent processing soft, weak, etc. references deferred from the prior phases of the GC.

 

Ref Enq

[Ref Enq: 0.1 ms]
Time spent placing soft, weak, etc. references on to the pending list.

 

Free CSet

[Free CSet: 2.0 ms]
Time spent freeing the set of regions that have just been collected, including their remembered sets.

 

總結

(終於到總結了,好累)

在這篇OBE中,你已經瞭解到了Java JVM中的G1垃圾收集器了。你要了解的第一個是Heap和GC什麼是任何Java JVM中的關鍵組件。接下來你要了解的是CMS和G1是如何工做的。接下來就是你要了解使用G1的時的命令行以及最佳實踐。最後就是你要知道GC日誌中記錄對象和數據。

 

在這篇教程中,你已經學到了:

Java JVM中的組件

G1垃圾收集器的概覽

CMS垃圾收集器的概覽

G1的命令行和最佳實踐

G1中的GC日誌

資源

訪問以下的網站能夠得到更多的資源

Java HotSpot VM Options

The Garbage First(G1) Garbage Collector

Poonam Bajaj G1 GC Blog Post

Java SE 7: Develop Rich Client Applications

Java Performance - Charlie Hunt and Binu John

Oracle Learning Library

致謝

Curriculum Developer: Michael J Williams

QA: Krishnanjani Chitta

相關文章
相關標籤/搜索