英文原文:cubrid,編譯:ImportNew- 王曉傑 html
本文是成爲Java GC專家系列文章的第二篇。在第一篇《深刻淺出Java垃圾回收機制》中咱們學習了不一樣GC算法的執行過程,GC是如何工做的,什麼是新生代和老年代,你應該瞭解的JDK7中的5種GC類型,以及這5種類型對於應用性能的影響。 java
在本文中,我將解釋JVM究竟是如何執行垃圾回收處理的。 算法
什麼是GC監控? bootstrap
垃圾回收收集監控指的是搞清楚JVM如何執行GC的過程,例如,咱們能夠查明:
windows
1. 什麼時候一個新生代中的對象被移動到老年代時,所花費的時間。 網絡
2. Stop-the-world 什麼時候發生的,持續了多長時間。 工具
GC監控是爲了鑑別JVM是否在高效地執行GC,以及是否有必要進行額外的性能調優。基於以上信息,咱們能夠修改應用程序或者調整GC算法(GC優化)。 性能
如何監控GC 學習
有不少種方法能夠監控GC,但其差異僅僅是GC操做經過何種方式展示而已。GC操做是由JVM來完成,而GC監控工具只是將JVM提供的GC信息展示給你,所以,不論你使用何種方式監控GC都將獲得相同的結果。因此你也就沒必要去學習全部的監控GC的方法。可是由於學習每種監控方法不會佔用太多時間,瞭解多一點能夠幫助你根據不一樣的場景選擇最爲合適的方式。 優化
下面所列的工具以及JVM參數並不適用於全部的HVM供應商。這是由於並無關於GC信息的強制標準。本文咱們將使用HotSpot JVM (Oracle JVM)。由於NHN 一直在使用Oracle (Sun) JVM,因此用它做爲示例來解釋咱們提到的工具和JVM參數更容易些。
首先,GC監控方法根據訪問的接口不一樣,能夠分紅CUI 和GUI 兩大類。CUI GC監控方法使用一個獨立的叫作」jstat」的CUI應用,或者在啓動JVM的時候選擇JVM參數」verbosegc」。
GUI GC監控由一個單獨的圖形化應用來完成,其中三個最經常使用的應用是」jconsole」, 「jvisualvm」 和 「Visual GC」。
下面咱們來詳細學習每種方法。
jstat
jstat 是HotSpot JVM提供的一個監控工具。其餘監控工具還有jps 和jstatd。有些時候,你可能須要同時使用三種工具來監控你的應用。jstat 不只提供GC操做的信息,還提供類裝載操做的信息以及運行時編譯器操做的信息。本文將只涉及jstat可以提供的信息中與監控GC操做信息相關的功能。
jstat 被放置在$JDK_HOME/bin。所以只要java 和 javac能執行,jstat 一樣能夠執行。
你能夠在命令行環境下執行以下語句。
1
2
3
4
5
6
7
8
|
$> 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
$>
|
在上圖的例子中,實際的數據會按照以下列輸出:
1
|
S0C S1C S0U S1U EC EU OC OU PC
|
vmid (虛擬機 ID),正如其名字描述的,它是虛擬機的ID,Java應用不論運行在本地仍是遠程的機器都會擁有本身獨立的vmid。運行在本地機器上的vmid稱之爲lvmid (本地vmid),一般是PID。若是想獲得PID的值你可使用ps命令或者windows任務管理器,但咱們推薦使用jps來獲取,由於PID和lvmid有時會不一致。jps 經過Java PS實現,jps命令會返回vmids和main方法的信息,正如ps命令展示PIDS和進程名字那樣。
首先經過jps命令找到你要監控的Java應用的vmid,並把它做爲jstat的參數。當幾個WAS實例運行在同一臺設備上時,若是你只使用jps命令,將只能看到啓動(bootstrap)信息。咱們建議在這種狀況下使用ps -ef | grep java與jps配合使用。
想要獲得GC性能相關的數據須要持續不斷地監控,所以在執行jstat時,要規則地輸出GC監控的信息。
例如,執行」jstat –gc 1000″ (或 1s)會每隔一秒展現GC監控數據。」jstat –gc 1000 10″會每隔1秒展示一次,且一共10次。
參數名稱 |
描述 |
gc |
輸出每一個堆區域的當前可用空間以及已用空間(伊甸園,倖存者等等),GC執行的總次數,GC操做累計所花費的時間。 |
gccapactiy |
輸出每一個堆區域的最小空間限制(ms)/最大空間限制(mx),當前大小,每一個區域之上執行GC的次數。(不輸出當前已用空間以及GC執行時間)。 |
gccause |
輸出-gcutil提供的信息以及最後一次執行GC的發生緣由和當前所執行的GC的發生緣由 |
gcnew |
輸出新生代空間的GC性能數據 |
gcnewcapacity |
輸出新生代空間的大小的統計數據。 |
gcold |
輸出老年代空間的GC性能數據。 |
gcoldcapacity |
輸出老年代空間的大小的統計數據。 |
gcpermcapacity |
輸出持久帶空間的大小的統計數據。 |
gcutil |
輸出每一個堆區域使用佔比,以及GC執行的總次數和GC操做所花費的事件。 |
你能夠只關心那些最經常使用的命令,你會常常用到 -gcutil (或-gccause), -gc and –gccapacity。
· -gcutil 被用於檢查堆間的使用狀況,GC執行的次數以及GC操做所花費的時間。
· -gccapacity以及其餘的參數能夠用於檢查實際分配內存的大小。
使用-gc 參數你能夠看到以下輸出:
1
2
3
4
|
S0C S1C … GCT
1248.0 896.0 … 1.246
1248.0 896.0 … 1.246
… … … …
|
不一樣的jstat參數輸出不一樣類型的列,以下表所示,根據你使用的」jstat option」會輸出不一樣列的信息。
列 | 說明 | Jstat參數 |
S0C | 輸出Survivor0空間的大小。單位KB。 | -gc -gccapacity -gcnew -gcnewcapacity |
S1C | 輸出Survivor1空間的大小。單位KB。 | -gc -gccapacity -gcnew -gcnewcapacity |
S0U | 輸出Survivor0已用空間的大小。單位KB。 | -gc -gcnew |
S1U | 輸出Survivor1已用空間的大小。單位KB。 | -gc -gcnew |
EC | 輸出Eden空間的大小。單位KB。 | -gc -gccapacity -gcnew -gcnewcapacity |
EU | 輸出Eden已用空間的大小。單位KB。 | -gc -gcnew |
OC | 輸出老年代空間的大小。單位KB。 | -gc -gccapacity -gcold -gcoldcapacity |
OU | 輸出老年代已用空間的大小。單位KB。 | -gc -gcold |
PC | 輸出持久代空間的大小。單位KB。 | -gc -gccapacity -gcold -gcoldcapacity -gcpermcapacity |
PU | 輸出持久代已用空間的大小。單位KB。 | -gc -gcold |
YGC | 新生代空間GC時間發生的次數。 | -gc -gccapacity -gcnew -gcnewcapacity -gcold -gcoldcapacity -gcpermcapacity -gcutil -gccause |
YGCT | 新生代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 -gcpermcapacity -gcutil -gccause |
NGCMN | 新生代最小空間容量,單位KB。 | -gccapacity -gcnewcapacity |
NGCMX | 新生代最大空間容量,單位KB。 | -gccapacity -gcnewcapacity |
NGC | 新生代當前空間容量,單位KB。 | -gccapacity -gcnewcapacity |
OGCMN | 老年代最小空間容量,單位KB。 | -gccapacity -gcoldcapacity |
OGCMX | 老年代最大空間容量,單位KB。 | -gccapacity -gcoldcapacity |
OGC | 老年代當前空間容量制,單位KB。 | -gccapacity -gcoldcapacity |
PGCMN | 持久代最小空間容量,單位KB。 | -gccapacity -gcpermcapacity |
PGCMX | 持久代最大空間容量,單位KB。 | -gccapacity -gcpermcapacity |
PGC | 持久代當前空間容量,單位KB。 | -gccapacity -gcpermcapacity |
PC | 持久代當前空間大小,單位KB | -gccapacity -gcpermcapacity |
PU | 持久代當前已用空間大小,單位KB | -gc -gcold |
LGCC | 最後一次GC發生的緣由 | -gccause |
GCC | 當前GC發生的緣由 | -gccause |
TT | 老年化閾值。被移動到老年代以前,在新生代空存活的次數。 | -gcnew |
MTT | 最大老年化閾值。被移動到老年代以前,在新生代空存活的次數。 | -gcnew |
DSS | 倖存者區所需空間大小,單位KB。 | -gcnew |
jstat 的好處是它能夠持續的監控GC操做數據,不論Java應用是運行在本地仍是遠程,只要有控制檯的地方就可使用。當使用–gcutil 會輸出以下信息。在GC優化的時候,你須要特別注意YGC, YGCT, FGC, FGCT 和GCT。
1
2
3
4
|
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處理到底花費了多少時間。
在這個例子中,YGC 是217而YGCT 是0.928,這樣在簡單的計算數據平均數後,你能夠知道每次新生代的GC大概須要4ms(0.004秒),而full GC的平均時間爲33ms。
可是,只看數據平均數常常沒法分析出真正的GC問題。這是主要是由於GC操做時間嚴重的誤差(換句話說,假如兩次full GC的時間是 67ms,那麼其中的一次full GC可能執行了10ms而另外一個可能執行了57ms。)爲了更好地檢測每次GC處理時間,最好使用 –verbosegc來替代數據平均數。
-verbosegc
-verbosegc 是在啓動一個Java應用時能夠指定的JVM參數之一。而jstat 能夠監控任何JVM應用,即使它沒有制定任何參數。 -verbosegc 須要在啓動的時候指定,所以你可能會認爲它沒有必要(由於jstat能夠替代之)。可是, -verbosegc 會以更淺顯易懂的方式展示GC發生的結果,所以他對於監控監控GC信息十分有用。
jstat | -verbosegc | |
監控對象 | 運行在本機的Java應用能夠把日誌輸出到終端上,或者藉助jstatd命令經過網絡鏈接遠程的Java應用。 | 只有那些把-verbogc做爲啓動參數的JVM。 |
輸出信息 | 堆狀態(已用空間,最大限制,GC執行次數/時間,等等) | 執行GC先後新生代和老年代空間大小,GC執行時間。 |
輸出時間 | Every designated time 每次設定好的時間。 |
每次GC發生的時候。 |
什麼時候有用。 | 當你試圖觀察堆空間變化狀況 | 當你試圖瞭解單次GC產生的效果。 |
下面是-verbosegc 的可用參數
· -XX:+PrintGCDetails
· -XX:+PrintGCTimeStamps
· -XX:+PrintHeapAtGC
· -XX:+PrintGCDateStamps (from JDK 6 update 4)
若是隻是用了 -verbosegc 。那麼默認會加上 -XX:+PrintGCDetails。 –verbosgc 的附加參數並非獨立的。而是常常組合起來使用。
使用 –verbosegc後,每次GC發生你都會看到以下格式的結果。
[GC [<collector>: <starting occupancy1> -> <ending occupancy1>, <pause time1> secs] <starting occupancy3> -> <ending occupancy3>, <pause time3> secs]
收集器 | minor gc使用的收集器的名字。 |
starting occupancy1 | GC執行前新生代空間大小。 |
ending occupancy1 | GC執行後新生代空間大小。 |
pause time1 | 由於執行minor GC,Java應用暫停的時間。 |
starting occupancy3 | GC執行前堆區域總大小 |
ending occupancy3 | GC執行後堆區域總大小 |
pause time3 | Java應用因爲執行堆空間GC(包括major GC)而中止的時間。 |
這是-verbosegc 輸出的minor GC的例子。
1
2
3
4
|
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
|
這是 Full GC發生時的例子
1
|
[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 collector,那麼以下CMS信息也會被輸出。
因爲 –verbosegc 參數在每次GC事件發生的時候都會輸出日誌,咱們能夠很輕易地觀察到GC操做對於堆空間的影響。
(Java) VisualVM + Visual GC
Java Visual VM是由Oracle JDK提供的圖形化的彙總和監控工具。
圖1: VisualVM 截圖
除了JDK中自帶的版本,你還能夠直接從官網下載Visual VM。出於便利性的考慮,JDK中包含的版本被命名爲Java VisualVM (jvisualvm),而官網提供的版本被命名爲Visual VM (visualvm)。二者的功能基本相同,只有一些細小的差異,例如安裝組件的時候。就我的而言,我更喜歡能夠從官網下載的Visual VM。
圖 2: Viusal GC 安裝截圖
經過Visual GC,你能夠更直觀的看到執行jstatd 所獲得的信息。
圖3: Visual GC 執行截圖
HPJMeter
HPJMeter 能夠很方便的分析 -verbosegc 輸出的結果,若是Visual GC能夠視做jstat的圖形化版本,那麼HPJMeter就至關於 –verbosgc的圖形化版本。固然,GC分析只是HPJMeter提供的衆多功能之一,HPJMeter是由惠普開發的性能監控工具,他能夠支持HP-UX,Linux以及MS Windows。
起初,一個成爲HPTune 被設計用來圖形化的分析-verbosegc.輸出的結果。可是,隨着HPTune的功能被集成到HPJMeter 3.0版本以後,就沒有必要單獨下載HPTune了。但運行一個應用時, -verbosegc 的結果會被輸出到一個獨立的文件中。
你能夠用HPJMeter直接打開這個文件,以便更直觀的分析GC性能數據。
圖4: HPJMeter
下次預告
本文咱們主要講述了若是監控GC操做信息,這將是GC優化的前提。就我我的經驗而言,我推薦使用jstat 來監控GC操做,若是你感受到GC操做的執行時間過長,那就可使用verbosegc 參數來分析GC。GC優化的大致步驟就是在添加verbosegc 參數後,調整GC參數,分析修改後的結果。在下一篇文章中,咱們將經過真實的例子來說解優化GC的最佳選擇。
做者Sangmin Lee, NHN公司,性能工程師實驗室高級工程師。