[譯]GC專家系列2:Java 垃圾回收的監控

原文連接:http://www.cubrid.org/blog/dev-platform/how-to-monitor-java-garbage-collection/java

這是GC專家系列文章的第二篇。在第一篇理解Java垃圾回收中咱們學習了幾種不一樣的GC算法的處理過程,GC的工做方式,新生代與老年代的區別。到目前爲止,你應該已經瞭解了JDK 7中的5種GC類型,以及每種GC對性能的影響。算法

在本篇中,我將介紹JVM在真實環境中如何運行GC的。segmentfault

什麼是GC監控

GC監控 指的是在運行時跟蹤JVM運行GC的過程。例如,經過GC監控,咱們能找出:網絡

  1. 什麼時候新生代的對象會被移動到老年代,有多少對象被移到了老年代。工具

  2. 什麼時候stop-the-world發生以及持續時間。性能

經過GC監控,能發現JVM是否在有效的運行GC以及是否須要額外的GC調優。基於這些信息,咱們能夠經過優化應用或者改變GC運行方式(GC調優),從而提升應用性能。學習

如何作GC監控

GC監控的方式不少,區別在於GC操做信息的展現會有所不一樣。GC是由JVM觸發,由於GC監控工具展現的信息都是由JVM提供,因此無論使用哪一種方式作GC監控,最終獲取的信息都是一致的。所以,沒有必要深刻學習每種GC監控工具,只須要花些時間學習每種工具的使用方法,可以在不一樣的場合選擇合適的工具便可。優化

由於JVM規範沒有要求暴露GC信息的標準方法,因此下面列出的工具或JVM選項並不能適用於全部不一樣的JVM實現。在下面的介紹中都是基於Hotspot JVM(Oracle JVM)進行。由於NHN使用的是Oracle(Sun) JVM,因此在使用如下工具或JVM選項時並不會太困難。網站

首先,GC監控工具根據訪問接口和方式不一樣分爲CUIGUI。經典的CUI 工具可使用一個單獨的CUI應用jstat,也能夠在運行JVM時經過提供"-verbosegc"選項來實現。spa

GUI GC監控工具經過單獨的GUI應用來實現,後面會介紹三個經常使用的GUI GC工具:jconsole, jvisualvm和Visual GC。

下面開始學習每一種GC監控方法:

jstat

jstat是Hotspot JVM內置的監控工具。Hotspot JVM還內置了其餘監控工具如jpsjstatd。有時候須要這三種工具一塊兒來監控Java應用的運行。

jstat 不僅提供GC操做的相關信息,也還提供類加載和即時編譯器相關的操做信息。儘管如此,本文咱們只會涉及jstat提供的GC操做相關的功能。

jstat 位於$JDK_HOME/bin目錄,若是java或javac命令可以正常運行,jstat命令也應該可以運行。

你能夠在命令行中嘗試一下:

$> jstat –gc  $<vmid$> 1000

S0C       S1C       S0U    S1U      EC         EU          OC         OU         PC         PU         YGC     YGCT    FGC      FGCT     GCT
3008.0   3072.0    0.0     1511.1   343360.0   46383.0     699072.0   283690.2   75392.0    41064.3    2540    18.454    4      1.133    19.588
3008.0   3072.0    0.0     1511.1   343360.0   47530.9     699072.0   283690.2   75392.0    41064.3    2540    18.454    4      1.133    19.588
3008.0   3072.0    0.0     1511.1   343360.0   47793.0     699072.0   283690.2   75392.0    41064.3    2540    18.454    4      1.133    19.588

$>

如上所示,真實的內存各部分數據狀況按如下各列順序列出:

SOC        S1C        S0U        S1U        EC        EU        OU        PC

vmid(虛擬機id: Virtual Machine ID),見名示意,表示VM的ID。運行在本地或遠程的虛擬機均可以經過vmid指定。運行在本地虛擬機上的Java應用的vmid又稱爲lvmid(Local vmid),一般與PID相同。雖然能夠經過ps命令或Windows的任務管理器查看PID的值從而獲得lvmid,但更推薦使用jps,由於PID和lvmid之間並不老是一一對應。jps表示Java PS。正如ps命令能夠看到PIDs和進程名,經過jps能夠看到vmids和main方法信息。

經過jps找到你要監控的Java應用的vmid,而後做爲jstat的參數便可。若是多個WAS實例運行在同一設備上時,若是隻使用jps命令只能找到引導程序的信息。這時候就要ps -ef | grep java命令和jps命令一塊兒使用。

GC性能數據須要持續觀察,所以在運行jstat時須要定時輸出GC的監控信息。

舉例來講:運行jstat -gc <vmid> 1000(or 1s)將會每隔1s在控制檯上輸出一次GC數據。jstat -gc <vmid> 1000 10將會每隔1s輸出一次GC數據,總共輸出10次。

與GC相關的選項除了-gc,還有其餘一些,以下表所示:

選項名稱 描述
gc 輸出堆空間上各分區當前的大小及使用量(Ede, Survivor, Old等),GC執行的總次數以及累積消耗的執行時長。
gccapacity 輸出堆空間上各分區的最小和最大容量,當前大小,每一個區上的GC執行次數(不輸出當前使用量和累積的GC耗時)。
gccause 除了輸出 -gcutil提供的信息外,還會輸出最後一次GC和當前GC的緣由。
gcnew 新生代上的GC性能數據。
gcnewcapacity 新生代容量的統計信息。
gcold 老年代的GC性能數據。
gcoldcapacity 老年代容量的統計信息。
gcpermcapacity 持久代(方法區)上的統計信息。
gcutil 以%的格式輸出每一個分區的使用量。同時也會輸出GC執行的總次數及累積耗時。

若是隻關心GC頻率,一般使用-gcutil(或者 -gccause), -gc, -gccapacity便可。

  • -gcutil 用於檢測各區上的使用量,GC執行次數以及累積耗時,

  • -gccapacity 和其餘的幾個選項可用於輸出實際已分配的內存大小。

使用-gc選項的輸出以下:

S0C         S1C    …    GCT
1248.0     896.0    …    1.246
1248.0      896.0    …    1.246
…         …        …    …

給jstat指定不一樣的選項會列出不一樣的列,以下列所示。表格右側列出了會輸出此信息的jstat選項。

數據列 描述 支持的jstat 選項
S0C Survivor0的當前容量 -gc
-gccapacity
-gcnew
-gcnewcapacity
S1C S1的當前容量 -gc
-gccapacity
-gcnew
-gcnewcapacity
S0U S0的使用量 -gc
-gcnew
S1U S1的使用量 -gc
-gcnew
EC Eden區的當前容量 -gc
-gccapacity
-gcnew
-gcnewcapacity
EU Eden區的使用量 -gc
-gcnew
OC old區的當前容量 -gc
-gccapacity
-gcnew
-gcnewcapacity
OU old區的使用量 -gc
-gcnew
PC 方法區的當前容量 -gc
-gccapacity
-gcold
-gcoldcapacity
-gcpermcapacity
PU 方法區的使用量 -gc
-gcold
YGC Young GC次數 -gc
-gccapacity
-gcnew
-gcnewcapacity
-gcold
-gcoldcapacity
-gcpermcapacity
-gcutil
-gccause
YGCT Young GC累積耗時 -gc
-gcnew
-gcutil
-gccause
FGC Full GC次數 -gc
-gccapacity
-gcnew
-gcnewcapacity
-gcold
-gcoldcapacity
-gcpermcapacity
-gcutil
-gccause
FGCT Full GC累積耗時 -gc
-gcold
-gcoldcapacity
-gcpermcapacity
-gcutil
-gccause
GCT GC總的累積耗時 -gc
-gcold
-gcoldcapacity
-gccapacity
-gcpermcapacity
-gcutil
-gccause
NGCMN 新生代最小容量 -gccapacity
-gcnewcapacity
NGCMX 新生代最大容量 -gccapacity
-gcnewcapacity
NGC 新生代當前容量 -gccapacity
-gcnewcapacity
OGCMN 老年代最小容量 -gccapacity
-gcoldcapacity
OGCMX 老年代最大容量 -gccapacity
-gcoldcapacity
OGC 老年代當前容量 -gccapacity
-gcoldcapacity
PGCMN 方法區最小容量 -gccapacity
-gcpermcapacity
PGCMX 方法區最大容量 -gccapacity
-gcpermcapacity
PGC 方法區當前容量 -gccapacity
-gcpermcapacity
PC 方法區的當前容量 -gccapacity
-gcpermcapacity
PU 方法區使用量 -gccapacity
-gcold
LGCC 上一次GC發生的緣由 -gccause
GCC 當前GC發生的緣由 -gccause
TT 存活閥值,若是對象在新生代移動次數超過此閥值,則會被移到老年代 -gcnew
MTT 最大存活閥值,若是對象在新生代移動次數超過此閥值,則會被移到老年代 -gcnew
DSS survivor區的理想容量 -gcnew

表格中容量數量單位爲:KB

jstat的優勢在於不論是本地仍是遠程Java應用,你均可以經過jstat命令查看GC操做相關的數據,並經過控制檯輸出這些信息。在使用-gcutil選項時,會輸出以下字段的信息。在作GC調優時,尤爲要關注YGC, YGCT, FGC, FGCTGCT的數據變化。

S0      S1       E        O        P        YGC    YGCT     FGC    FGCT     GCT
0.00    66.44    54.12    10.58    86.63    217    0.928     2     0.067    0.995
0.00    66.44    54.12    10.58    86.63    217    0.928     2     0.067    0.995
0.00    66.44    54.12    10.58    86.63    217    0.928     2     0.067    0.995

這些信息很是重要,它統計了GC運行時的耗時狀況,能反映出GC的性能指標。

在上例中,YGC是217次, YGCT爲0.928,平均下來每次young GC耗時4ms(0.004 s)。一樣可算出full GC的平均耗時爲33ms。

然而平均值對發現實現的GC問題並無太大的幫助,由於每次GC耗時一般會有巨大的誤差(也就是說,若是full GC的平均值爲0.067s,可能意味着其中一次GC耗時1ms,而另一次持續134ms)。爲了能觀察每次GC的獨立耗時而非平均值,更好的方式是使用-verbosegc

-verbosegc

-verbosegc 是運行Java應用時的一個JVM選項。jstat能夠監控任何JVM應用而無需指定啓動參數,-verbosegc去要在開啓應用時就指定好,因此看起來-verbosegc並非一個必要的選項(由於可使用jstat完成相同工做)。然而當GC發生時-verbosegc的輸出信息更容易理解,這對於監控煩雜的GC信息卻大於益處。

jstat -verbosegc
監控目標 可輸出日誌到終端上的Java應用或者能經過jstatd鏈接到網絡的遠程Java應用 在啓動JVM時指定了-verbosegc 參數的Java應用
輸出信息 堆狀態(使用量、最大容量、GC次數及累積耗時等) 每次GC先後新生代和老年代的容量變化及GC耗時
輸出時機 任何指定的時間 任何GC發生時
優點 方便連續觀察堆大小的變化 觀察單次GC對系統的影響

在使用-verbosegc時還可同時指定如下附加選項:

  • -XX:+PrintGCDetails

  • -XX:+PrintGCTimeStamps

  • -XX:+PrintHeapAtGC

  • -XX:+PrintGCDateStamps(JDK6U4引入的選項)

若是隻是指定了-verbosegc選項,則默認會同時指定-XX:+PrintGCDetails。另外,-verbosegc的附加選項均可以組合使用。

使用-verbosegc後,當有minor GC發生時,輸出的數據格式以下:

[GC [<collector>: <starting occupancy1> -> <ending occupancy1>, <pause time1> secs] <starting occupancy3> -> <ending occupancy3>, <pause time3> secs]
字段 含義
Collector 使用的收集器
starting occupancy1 GC發生前的新生代大小
ending occupancy1 GC後新生代的大小
pause time1 執行minor GC時Java應用停頓的時長
starting occupancy3 GC發生前堆空間總大小
ending occupancy3 GC發生後堆空間總大小
pause time3 執行整體GC(包括Full GC)時Java應用停頓時長

下面是一個Full GC輸出的例子:

[Full GC [Tenured: 3485K->4095K(4096K), 0.1745373 secs] 61244K->7418K(63104K), [Perm : 10756K->10756K(12288K)], 0.1762129 secs] [Times: user=0.19 sys=0.00, real=0.19 secs]

若是使用了[CMS回收算法](),CMS相關信息也會緊接着提供出來。

由於-verbosegc選項能夠把每次GC發生時的信息都以log方式輸出,因此很容易觀察GC操做關後heap使用率的變化狀況。

(Java) VisualVM + Visual GC

Java Virsual VM是Oracle JDK提供的一個GUI式的圖表/監控工具。

VisrualVM 截圖
圖1:VirsualVM 界面

與內置在JDK中的版本不一樣,你能夠在網站上單獨下載Virsual VM。方便起見,JDK內置的版本稱爲Java VirsualVM(jvisualvm),從網站上單獨下載的稱爲Virsual VM(visualvm)。兩者之間的特性並不徹底一致,在一些方面(例如安裝插件等)會有細微的差異。就我我的而言,更偏向於使用單獨下載的Virsual VM。

啓動Visual VM後,若是你左側面板上選擇了但願監控的應用,就會看到"Monitoring"一欄。從Monitoring欄中能夠得到關於GC和內存堆的基本信息。

儘管能經過Visual VM的基本特性獲得GC的基本狀態,但並不能像使用jstat-verbosegc同樣得到更詳細的信息。

若是想獲得像jstat同樣的詳細信息,則須要安裝相應的Virsual VM插件。能夠在Tools菜單裏獲取Virsual GC插件。

Virsual GC安裝界面
圖2:Virsual GC安裝界面

經過Virsual GC,能夠以更直觀的方式得到jstatd提供的信息。

Virsual GC運行界面
圖3:Virsual GC運行界面

HPJMeter

HPJMeter是一個分析-verbosegc輸出結果的便捷工具。若是把Visual GC看做是jstat的GUI版本,那麼HPJMeter則是-verbosegc的GUI版本。話說回來,GC分析只是HPJMeter提供的衆多特性之一。HPJMeter是HP公司開發的一款性能監控工具,可使用在HP-UX,Linux和MS Windows上。

起初,只是一款叫作HPTune的工具提供GUI的方式分析-verbosegc。自從HPJMeter 3.0開始便集成了HPTune,所以無需再單獨下載HPTune。

在應用運行過程當中,-verbosegc的輸出結果能夠重定向到一個單獨的文件中。

能夠經過HPJMeter打開該文件,而後使用直觀的GUI界面便捷的分析GC數據。

HPJMeter
圖4:HPJMeter

下章介紹

本章做爲GC調優的鋪墊,着重於介紹瞭如何進行GC信息監控。通常狀況我比較建議先使用jstat觀察GC操做,當發現有比較耗時的GC後,再經過-verbosegc來分析GC數據。所以GC調優的通常過程就是分析和對比使用不一樣GC選項後-verbosegc輸出結果的變化。下章將會經過真實案例來介紹進行GC調優的最佳選項。

做者:Sangmin Lee, 性能實驗室高級工程師,NHN公司

相關文章
相關標籤/搜索