troubleshoot之:使用JFR分析性能問題
簡介
java程式的性能問題分析是一個很困難的問題。尤其是對於一個非常複雜的程式來說,分析起來更是頭疼。
還好JVM引入了JFR,可以通過JFR來監控和分析JVM的各種事件。通過這些事件的分析,我們可以找出潛在的問題。
今天我們就來介紹一下對java性能分析比較重要的一些JFR事件。
GC性能事件
一般來說,GC會對java程式的性能操作產生比較重要的影響。我們可以使用jfr監控jdk.GCPhasePause事件。
下面是一個jdk.GCPhasePause的例子:
jfr print --events jdk.GCPhasePause flight_recording_1401comflydeanTestMemoryLeak89268.jfr
輸出結果:
jdk.GCPhasePause {
startTime = 19:51:49.798
duration = 41.1 ms
gcId = 2
name = "GC Pause"
}
通過GCPhasePause事件,我們可以統計總的GC pause時間和平均每一次GC pause的時間。
一般來說GC是在後台執行的,所以GC本身的執行時間我們並不需要關注,因為這並不會影響到程式的性能。我們需要關注的是應用程式因為GC暫停的時間。
考慮下面兩種情況,第一種單獨的GC導致GC pause時間過長。第二種是總的GC pause時間過長。
如果是第一種情況,那麼可能需要考慮換一個GC類型,因為不同的GC類型在pause時間和吞吐量的平衡直接會有不同的處理。同時我們需要減少finalizers的使用。
如果是第二種情況,我們可以從下面幾個方面來解決。
-
增加heap空間大小。heap空間越大,GC的間隔時間就越長。總的GC pause時間就會越短。
-
盡量減少tmp對象的分配。我們知道為了提升多執行緒的性能,JVM會使用TLAB技術。一般來說小對象會分配在TLAB中,但如果是大對象,則會直接分配在heap空間中。但是大部分對象都是在TLAB中分配的。所以我們可以同時關注TLAB和TLAB之外的兩個事件:jdk.ObjectAllocationInNewTLAB和dk.ObjectAllocationOutsideTLAB。
-
減少分配頻率。我們可以通過jdk.ThreadAllocationStatistics來分析。
同步性能
在多執行緒環境中,因為多執行緒會競爭共享資源,所以對資源的同步,或者鎖的使用都會影響程式的性能。
我們可以監控jdk.JavaMonitorWait事件。
jfr print --events jdk.JavaMonitorWait flight_recording_1401comflydeanTestMemoryLeak89268.jfr
我們看一個結果:
jdk.JavaMonitorWait {
startTime = 19:51:25.395
duration = 2 m 0 s
monitorClass = java.util.TaskQueue (classLoader = bootstrap)
notifier = N/A
timeout = 2 m 0 s
timedOut = true
address = 0x7FFBB7007F08
eventThread = "JFR Recording Scheduler" (javaThreadId = 17)
stackTrace = [
java.lang.Object.wait(long)
java.util.TimerThread.mainLoop() line: 553
java.util.TimerThread.run() line: 506
]
}
通過分析JavaMonitorWait事件,我們可以找到競爭最激烈的鎖,從而進行更深層次的分析。
IO性能
如果應用程式有很多IO操作,那麼IO操作也是會影響性能的關鍵一環。
我們可以監控兩種IO類型:socket IO和File IO。
相對應的事件有:dk.SocketWrite,jdk.SocketRead,jdk.FileWrite,jdk.FileRead。
程式碼執行的性能
程式碼是通過CPU來運行的,如果CPU使用過高,也可能會影響到程式的性能。
我們可以通過監聽jdk.CPULoad事件來對CPULoad進行分析。
jfr print --events jdk.CPULoad flight_recording_1401comflydeanTestMemoryLeak89268.jfr
看下運行結果:
jdk.CPULoad {
startTime = 19:53:25.519
jvmUser = 0.63%
jvmSystem = 0.37%
machineTotal = 20.54%
}
如果jvm使用的cpu比較少,但是整個machine的CPU使用率比較高,這說明了有其他的程式在佔用CPU。
如果JVM自己的CPU使用就很高的話,那麼就需要找到這個佔用CPU的執行緒進行進一步分析。
其他有用的event
除了上面提到的event之外,還有一些其他有用的我們可以關注的event。
比如執行緒相關的:jdk.ThreadStart,jdk.ThreadEnd,jdk.ThreadSleep,jdk.ThreadPark。
如果你使用JMC,那麼可以很直觀的查看JFR的各種事件。
所以推薦大家使用JMC。
本文作者:flydean程式那些事
本文鏈接://www.flydean.com/jvm-diagnostic-perform-issue/
本文來源:flydean的部落格
歡迎關注我的公眾號:程式那些事,更多精彩等著您!