當事情變得不對勁并且我試圖確定原因時,我接觸了Java性能分析工具。 這些工具有兩種形式,一種是精美的GUI(稱為visualvm) ,當我在本地計算機上工作時會使用它;另一種是Java開發工具包(JDK)附帶的cli工具(當我在遠程工作時使用)。
我指的CLI工具是:
- jps – JVM進程狀態工具
- jstat – JVM統計信息監視工具
- jhat – Java堆分析工具
- jstack – Java堆棧跟蹤工具
我最常用的工具是jps,jstat和jstack,jahat工具也非常方便,但實際上確實需要一個完整的博客文章,因為您瘋狂地使用它可以做什么。 在這篇文章中,我整理了一些技巧,觀察和示例輸出,以說明如何使用它們。
當我使用ubuntu 11.10(僅安裝Java運行時環境(JRE))時,我將需要安裝JDK。 就我而言,我決定嘗試一下openjdk 7,但是版本6可以正常工作。
root@oneric:~# apt-get install openjdk-7-jdk
要嘗試這些命令,我??已經安裝了tomcat7,可以通過ubuntu上的apt來完成,同樣,以前的版本是tomcat 6。
root@oneric:~# apt-get install tomcat7
現在我已經安裝了tomcat,我想列出Java進程,請注意,這樣做時最好假定使用與服務相同的用戶帳戶。 在ubuntu上,我將使用用戶帳戶,因為tomcat7用戶是系統帳戶,我必須覆蓋shell,因為默認情況下它是/ bin / nologin ,然后我可以以該用戶身份運行jps。
jps命令輸出java進程的PID以及啟動時傳遞給它的主類名稱和參數。
root@oneric:~# su - tomcat7 -s /bin/bash
tomcat7@oneric:~$ jps -ml
12728 org.apache.catalina.startup.Bootstrap start
13926 sun.tools.jps.Jps -ml
tomcat7@oneric:~$
現在我們有了這些進程的PID,可以運行jstat了,我使用的第一個開關是-gcutil,這使我對jvm中的堆使用有了一個總體了解。 如果出現暫停或性能下降的情況,我將查看最后兩列。 其中包含垃圾收集時間(GCT)和完整垃圾收集時間(FGCT)。 如果FGCT列每秒增加一次,則可能是我們遇到了問題。
下面的示例針對tomcat的PID運行jstat 。 我還指示該命令每20行顯示表頭并以1000毫秒的間隔連續打印統計信息,就像正常的控件C一樣,在輸出末尾顯示。
此示例顯示了一個很少發生的新啟動的tomcat 7,這從完全垃圾收集時間(FGCT)和垃圾收集時間(GCT)列中的值可以清楚地看出。
還要注意的是,目前的Permgen空間(P)占70%。 permgen空間是堆的重要區域,因為它保存用戶類,方法名稱和內部jvm對象。 如果您使用tomcat已有一段時間,您將看到java.lang.OutOfMemoryError:PermGen空間錯誤,該錯誤指示何時該空間被填滿并且無法被垃圾回收。 重新部署大型Web應用程序時經常發生這種情況。
同樣在示例中,我們可以看到幸存者0(S0),幸存者1(S1),伊甸園和舊空間具有相當大的可用空間。
tomcat7@oneric:~$ jstat -gcutil -h20 12728 1000S0 S1 E O P YGC YGCT FGC FGCT GCT 0.00 17.90 32.12 4.81 71.41 5 0.009 1 0.023 0.0320.00 17.90 32.12 4.81 71.41 5 0.009 1 0.023 0.0320.00 17.90 32.12 4.81 71.41 5 0.009 1 0.023 0.032
為了說明相比之下,tomcat的負載情況,我們可以安裝一個稱為Apache Bench的工具。
root@oneric:~# apt-get install apache2-utils
并運行以下命令以同時訪問具有大量請求的基本頁面。
markw@oneric:~$ ab -n 1000000 -c 100 http://localhost:8080/
下面是該測試運行了一段時間后的輸出,因為我們可以看到幸存者1,伊甸園和舊空間有了相當大的增長,但是服務器并沒有花費很多時間來進行完整的垃圾收集,如下所示完整垃圾收集計數(FGC)的值只有10,從年輕一代收集計數(YGC)的增加可以看出,大部分工作是在年輕一代中進行的。
還要注意的是,permgen空間沒有太多變化,實際上下降了,這是由于堆大小的增加。
tomcat7@oneric:~$ jstat -gcutil -h20 12728 1000S0 S1 E O P YGC YGCT FGC FGCT GCT 0.00 100.00 52.02 81.84 59.62 117 1.176 10 0.074 1.2500.00 100.00 52.02 81.84 59.62 117 1.176 10 0.074 1.2500.00 100.00 52.02 81.84 59.62 117 1.176 10 0.074 1.2500.00 100.00 52.02 81.84 59.62 117 1.176 10 0.074 1.250
為了更深入地了解垃圾收集的原因,我們使用了帶有-gccause選項的jstat命令,該命令顯示的列與上一個命令相同,但有兩個額外的列提供了GC的原因。
在下面的示例中,我們可以看到分配失敗的示例,這表明由于堆太小,正在執行完整的gc。
tomcat7@oneric:~$ jstat -gccause -h20 12728 1000
100.00 0.00 0.00 78.91 59.67 168 1.680 14 0.083 1.763 unknown GCCause No GC
100.00 0.00 72.61 83.73 59.67 170 1.698 14 0.083 1.781 unknown GCCause No GC 0.00 100.00 46.24 91.83 59.67 173 1.729 14 0.083 1.811 unknown GCCause No GC
100.00 0.00 11.39 29.80 59.67 176 1.759 16 0.086 1.846 unknown GCCause No GC
100.00 0.00 92.41 35.30 59.67 179 1.777 16 0.086 1.864 unknown GCCause Allocation Failure 0.00 100.00 62.58 43.05 59.67 181 1.803 16 0.086 1.889 unknown GCCause No GC
診斷性能問題時,我還想研究的另一個領域是虛擬機中運行的線程。 這可以幫助我理解是否有任何組件超載,因此可以運行許多線程來追趕。 這主要僅適用于異步過程,例如消息傳遞或調度例程。
要轉儲線程及其當前堆棧的列表,請使用jstack命令,如下面的示例所示,我通常再次以進程所有者的身份運行它。
tomcat7@oneric:~$ jstack 12728
2011-10-16 14:53:58
Full thread dump OpenJDK 64-Bit Server VM (20.0-b11 mixed mode):"Attach Listener" daemon prio=10 tid=0x00000000015be800 nid=0x4004 waiting on condition [0x0000000000000000]java.lang.Thread.State: RUNNABLE"http-bio-8080-exec-182" daemon prio=10 tid=0x00007f9d84274800 nid=0x3cd3 waiting on condition [0x00007f9d7a0df000]java.lang.Thread.State: WAITING (parking)at sun.misc.Unsafe.park(Native Method)- parking to wait for <0x00000000ef16da38> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject. await(AbstractQueuedSynchronizer.java:2043)at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:386)at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:104)at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:32)at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1043)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1103)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)at java.lang.Thread.run(Thread.java:679)
...
我計劃用jruby在一些可視化工具上做一些工作,但是這可能是我下一篇文章的重點。 在撰寫本文的過程中,我找到了一些有趣的文章,這些文章鏈接如下:
- Sun Microsystems的Chuk-Munn Lee對Java SE 6部署進行故障排除
- 解釋java.lang.OutOfMemoryError:PermGen空間
參考: Mark Wolfe博客上的 JCG合作伙伴 Mark Wolfe 從CLI監視OpenJDK 。
- 任何軟件開發公司應存在的服務,實踐和工具,第1部分
- 這是在您的業務邏輯之前!
- 您的代碼中有幾個錯誤?
- 使用FindBugs產生更少的錯誤代碼
- 引入新技術–如何抵抗阻力
- Java工具:源代碼優化和分析
- 我們可以更好地理解需求規范嗎?
- 每個程序員都應該知道的事情
- 為什么自動化測試可以提高您的開發速度
翻譯自: https://www.javacodegeeks.com/2011/10/monitoring-openjdk-from-cli.html