troubleshoot之:使用JFR分析性能问题
文章目錄
- 簡介
- GC性能事件
- 同步性能
- IO性能
- 代碼執(zhí)行的性能
- 其他有用的event
簡介
java程序的性能問題分析是一個(gè)很困難的問題。尤其是對(duì)于一個(gè)非常復(fù)雜的程序來說,分析起來更是頭疼。
還好JVM引入了JFR,可以通過JFR來監(jiān)控和分析JVM的各種事件。通過這些事件的分析,我們可以找出潛在的問題。
今天我們就來介紹一下對(duì)java性能分析比較重要的一些JFR事件。
GC性能事件
一般來說,GC會(huì)對(duì)java程序的性能操作產(chǎn)生比較重要的影響。我們可以使用jfr監(jiān)控jdk.GCPhasePause事件。
下面是一個(gè)jdk.GCPhasePause的例子:
jfr print --events jdk.GCPhasePause flight_recording_1401comflydeanTestMemoryLeak89268.jfr輸出結(jié)果:
jdk.GCPhasePause {startTime = 19:51:49.798duration = 41.1 msgcId = 2name = "GC Pause" }通過GCPhasePause事件,我們可以統(tǒng)計(jì)總的GC pause時(shí)間和平均每一次GC pause的時(shí)間。
一般來說GC是在后臺(tái)執(zhí)行的,所以GC本身的執(zhí)行時(shí)間我們并不需要關(guān)注,因?yàn)檫@并不會(huì)影響到程序的性能。我們需要關(guān)注的是應(yīng)用程序因?yàn)镚C暫停的時(shí)間。
考慮下面兩種情況,第一種單獨(dú)的GC導(dǎo)致GC pause時(shí)間過長。第二種是總的GC pause時(shí)間過長。
如果是第一種情況,那么可能需要考慮換一個(gè)GC類型,因?yàn)椴煌腉C類型在pause時(shí)間和吞吐量的平衡直接會(huì)有不同的處理。同時(shí)我們需要減少finalizers的使用。
如果是第二種情況,我們可以從下面幾個(gè)方面來解決。
-
增加heap空間大小。heap空間越大,GC的間隔時(shí)間就越長??偟腉C pause時(shí)間就會(huì)越短。
-
盡量減少tmp對(duì)象的分配。我們知道為了提升多線程的性能,JVM會(huì)使用TLAB技術(shù)。一般來說小對(duì)象會(huì)分配在TLAB中,但如果是大對(duì)象,則會(huì)直接分配在heap空間中。但是大部分對(duì)象都是在TLAB中分配的。所以我們可以同時(shí)關(guān)注TLAB和TLAB之外的兩個(gè)事件:jdk.ObjectAllocationInNewTLAB和dk.ObjectAllocationOutsideTLAB。
-
減少分配頻率。我們可以通過jdk.ThreadAllocationStatistics來分析。
同步性能
在多線程環(huán)境中,因?yàn)槎嗑€程會(huì)競爭共享資源,所以對(duì)資源的同步,或者鎖的使用都會(huì)影響程序的性能。
我們可以監(jiān)控jdk.JavaMonitorWait事件。
jfr print --events jdk.JavaMonitorWait flight_recording_1401comflydeanTestMemoryLeak89268.jfr我們看一個(gè)結(jié)果:
jdk.JavaMonitorWait {startTime = 19:51:25.395duration = 2 m 0 smonitorClass = java.util.TaskQueue (classLoader = bootstrap)notifier = N/Atimeout = 2 m 0 stimedOut = trueaddress = 0x7FFBB7007F08eventThread = "JFR Recording Scheduler" (javaThreadId = 17)stackTrace = [java.lang.Object.wait(long)java.util.TimerThread.mainLoop() line: 553java.util.TimerThread.run() line: 506] }通過分析JavaMonitorWait事件,我們可以找到競爭最激烈的鎖,從而進(jìn)行更深層次的分析。
IO性能
如果應(yīng)用程序有很多IO操作,那么IO操作也是會(huì)影響性能的關(guān)鍵一環(huán)。
我們可以監(jiān)控兩種IO類型:socket IO和File IO。
相對(duì)應(yīng)的事件有:dk.SocketWrite,jdk.SocketRead,jdk.FileWrite,jdk.FileRead。
代碼執(zhí)行的性能
代碼是通過CPU來運(yùn)行的,如果CPU使用過高,也可能會(huì)影響到程序的性能。
我們可以通過監(jiān)聽jdk.CPULoad事件來對(duì)CPULoad進(jìn)行分析。
jfr print --events jdk.CPULoad flight_recording_1401comflydeanTestMemoryLeak89268.jfr看下運(yùn)行結(jié)果:
jdk.CPULoad {startTime = 19:53:25.519jvmUser = 0.63%jvmSystem = 0.37%machineTotal = 20.54% }如果jvm使用的cpu比較少,但是整個(gè)machine的CPU使用率比較高,這說明了有其他的程序在占用CPU。
如果JVM自己的CPU使用就很高的話,那么就需要找到這個(gè)占用CPU的線程進(jìn)行進(jìn)一步分析。
其他有用的event
除了上面提到的event之外,還有一些其他有用的我們可以關(guān)注的event。
比如線程相關(guān)的:jdk.ThreadStart,jdk.ThreadEnd,jdk.ThreadSleep,jdk.ThreadPark。
如果你使用JMC,那么可以很直觀的查看JFR的各種事件。
所以推薦大家使用JMC。
本文作者:flydean程序那些事
本文鏈接:http://www.flydean.com/jvm-diagnostic-perform-issue/
本文來源:flydean的博客
歡迎關(guān)注我的公眾號(hào):程序那些事,更多精彩等著您!
總結(jié)
以上是生活随笔為你收集整理的troubleshoot之:使用JFR分析性能问题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: troubleshoot之:分析OutO
- 下一篇: troubleshoot之:GC调优到底