超好用的自带火焰图的 Java 性能分析工具 Async-profiler 了解一下
如果你經(jīng)常遇到 Java 線上性能問題束手無策,看著線上服務(wù) CPU 飆升一籌莫展,發(fā)現(xiàn)內(nèi)存不斷泄露滿臉茫然。別慌,這里有一款低開銷、自帶火焰圖、讓你大呼好用的 Java 性能分析工具 -?async-profiler。
最近 Arthas 性能分析工具上線了火焰圖分析功能,Arthas 使用?async-profiler?生成 CPU/內(nèi)存火焰圖進(jìn)行性能分析,彌補(bǔ)了之前內(nèi)存分析的不足。在 Arthas 上使用還是比較方便的,使用方式可以看官方文檔。這篇文章介紹?async-profiler?相關(guān)內(nèi)容。
Arthas 火焰圖官方文檔:https://alibaba.github.io/arthas/profiler.html
async-profiler 介紹
async-profiler 是一款開源的 Java?性能分析工具,原理是基于 HotSpot 的 API,以微乎其微的性能開銷收集程序運(yùn)行中的堆棧信息、內(nèi)存分配等信息進(jìn)行分析。
使用 async-profiler 可以做下面幾個(gè)方面的分析。
CPU cycles
Hardware and Software performance counters like cache misses, branch misses, page faults, context switches etc.
Allocations in Java Heap
Contented lock attempts, including both Java object monitors and ReentrantLocks
我們常用的是 CPU 性能分析和 Heap 內(nèi)存分配分析。在進(jìn)行 CPU 性能分析時(shí),僅需要非常低的性能開銷就可以進(jìn)行分析,這也是這個(gè)工具的優(yōu)點(diǎn)之一。
在進(jìn)行 Heap 分配分析時(shí),async-profiler 工具會(huì)收集內(nèi)存分配信息,而不是去檢測占用 CPU 的代碼。async-profiler 不使用侵入性的技術(shù),例如字節(jié)碼檢測工具或者探針檢測等,這也說明 async-profiler 的內(nèi)存分配分析像 CPU 性能分析一樣,不會(huì)產(chǎn)生太大的性能開銷,同時(shí)也不用寫出龐大的堆棧文件再去進(jìn)行進(jìn)一步處理,。
async-profile 目前支持 Linux 和 macOS 平臺(tái)(macOS 下只能分析用戶空間的代碼)。
Linux?/ x64 / x86 / ARM / AArch64
macOS?/ x64
async-profiler 工具在采樣后可以生成采樣結(jié)果的日志報(bào)告,也可以生成 SVG 格式的火焰圖,在之前生成火焰圖要使用 FlameGraph 工具。現(xiàn)在已經(jīng)不需要了,從 1.2 版本開始,就已經(jīng)內(nèi)置了開箱即用的 SVG 文件生成功能。
其他信息可以看官方文檔:https://github.com/jvm-profiling-tools/async-profiler
async-profiler 安裝
下載 async-profiler 工具可以在官方的 Github 上直接下載編譯好的文件,如果你就是想體驗(yàn)手動(dòng)擋的感覺,也可以克隆項(xiàng)目,手動(dòng)編譯一下,不得不說這個(gè)工具十分的易用,我在手動(dòng)編譯的過程十分順滑,沒有出現(xiàn)任何問題。
如果你想下載編譯好的,可以到這里下載。
https://github.com/jvm-profiling-tools/async-profiler/releases
如果想體驗(yàn)手動(dòng)擋的感覺,可以克隆整個(gè)項(xiàng)目,進(jìn)項(xiàng)項(xiàng)目編譯。
手動(dòng)編譯的環(huán)境要求。
JDK
GCC
下面是手動(dòng)安裝的操作命令。
git?clone?https://github.com/jvm-profiling-tools/async-profiler cd?async-profiler make執(zhí)行 make 命令編譯后會(huì)在項(xiàng)目的目錄下生成一個(gè) build 文件夾,里面存放著編譯的結(jié)果。下面是我手動(dòng)編譯的過程輸出。
???develop?git?clone?https://github.com/jvm-profiling-tools/async-profiler Cloning?into?'async-profiler'... remote:?Enumerating?objects:?69,?done. remote:?Counting?objects:?100%?(69/69),?done. remote:?Compressing?objects:?100%?(54/54),?done. remote:?Total?1805?(delta?34),?reused?32?(delta?15),?pack-reused?1736 Receiving?objects:?100%?(1805/1805),?590.78?KiB?|?23.00?KiB/s,?done. Resolving?deltas:?100%?(1288/1288),?done. ???develop?cd?async-profiler ???async-profiler?git:(master)?make mkdir?-p?build g++?-O2?-D_XOPEN_SOURCE?-D_DARWIN_C_SOURCE?-DPROFILER_VERSION=\"1.6\"?-I/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/include?-I/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/include/darwin?-fPIC?-shared?-o?build/libasyncProfiler.so?src/*.cpp?-ldl?-lpthread gcc?-O2?-DJATTACH_VERSION=\"1.5\"?-o?build/jattach?src/jattach/jattach.c mkdir?-p?build/classes /Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/bin/javac?-source?6?-target?6?-d?build/classes?src/java/one/profiler/AsyncProfiler.java?src/java/one/profiler/AsyncProfilerMXBean.java?src/java/one/profiler/Counter.java?src/java/one/profiler/Events.java 警告:?[options]?未與?-source?1.6?一起設(shè)置引導(dǎo)類路徑 1?個(gè)警告 /Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/bin/jar?cvf?build/async-profiler.jar?-C?build/classes?. 已添加清單 正在添加:?one/(輸入?=?0)?(輸出?=?0)(存儲(chǔ)了?0%) 正在添加:?one/profiler/(輸入?=?0)?(輸出?=?0)(存儲(chǔ)了?0%) 正在添加:?one/profiler/AsyncProfiler.class(輸入?=?1885)?(輸出?=?908)(壓縮了?51%) 正在添加:?one/profiler/Events.class(輸入?=?405)?(輸出?=?286)(壓縮了?29%) 正在添加:?one/profiler/Counter.class(輸入?=?845)?(輸出?=?473)(壓縮了?44%) 正在添加:?one/profiler/AsyncProfilerMXBean.class(輸入?=?631)?(輸出?=?344)(壓縮了?45%) rm?-rf?build/classes ???async-profiler?git:(master)async-profiler 使用
運(yùn)行項(xiàng)目里的 profiler.sh 可以看到 async-profiler 的使用幫助文檔。
???async-profiler?git:(master)?./profiler.sh Usage:?./profiler.sh?[action]?[options]?<pid> Actions:start?????????????start?profiling?and?return?immediatelyresume????????????resume?profiling?without?resetting?collected?datastop??????????????stop?profilingstatus????????????print?profiling?statuslist??????????????list?profiling?events?supported?by?the?target?JVMcollect???????????collect?profile?for?the?specified?period?of?timeand?then?stop?(default?action) Options:-e?event??????????profiling?event:?cpu|alloc|lock|cache-misses?etc.-d?duration???????run?profiling?for?<duration>?seconds-f?filename???????dump?output?to?<filename>-i?interval???????sampling?interval?in?nanoseconds-j?jstackdepth????maximum?Java?stack?depth-b?bufsize????????frame?buffer?size-t????????????????profile?different?threads?separately-s????????????????simple?class?names?instead?of?FQN-g????????????????print?method?signatures-a????????????????annotate?Java?method?names-o?fmt????????????output?format:?summary|traces|flat|collapsed|svg|tree|jfr-v,?--version?????display?version?string--title?string????SVG?title--width?px????????SVG?width--height?px???????SVG?frame?height--minwidth?px?????skip?frames?smaller?than?px--reverse?????????generate?stack-reversed?FlameGraph?/?Call?tree--all-kernel??????only?include?kernel-mode?events--all-user????????only?include?user-mode?events--sync-walk???????use?synchronous?JVMTI?stack?walker?(dangerous!)<pid>?is?a?numeric?process?ID?of?the?target?JVMor?'jps'?keyword?to?find?running?JVM?automaticallyExample:?./profiler.sh?-d?30?-f?profile.svg?3456./profiler.sh?start?-i?999000?jps./profiler.sh?stop?-o?summary,flat?jps可以看到使用的方式是:Usage: ./profiler.sh [action] [options]?,也就是?命令+操作+參數(shù)+PID。
常用的使用的幾個(gè)步驟:
查看 java 進(jìn)程的 PID(可以使用 jps )。
使用 ./profiler.sh start?
開始采樣。使用 ./profiler.sh status?
查看已經(jīng)采樣的時(shí)間。使用 ./profiler.sh stop?
停止采樣,輸出結(jié)果。這種方式使用起來多費(fèi)勁啊,而且最后輸出的是文本結(jié)果,看起來更是費(fèi)勁,為了不那么費(fèi)勁,可以使用幫助里給的采樣后生成 SVG 文件例子。
./profiler.sh?-d?30?-f?profile.svg?3456這個(gè)命令的意思是,對 PID 為 3456 的 java 進(jìn)程采樣 30 秒,然后生成 profile.svg 結(jié)果文件。
默認(rèn)情況下是分析 CPU 性能,如果要進(jìn)行其他分析,可以使用 -e 參數(shù)。
-e?event?????profiling?event:?cpu|alloc|lock|cache-misses?etc.可以看到支持的分析事件有 CPU、Alloc、Lock、Cache-misses 。
async-profiler 案例
上面說完了 async-profiler 工具的作用和使用方式,既然能進(jìn)行 CPU 性能分析和 Heap 內(nèi)存分配分析,那么我們就寫幾個(gè)不一般的方法分析試試看。看看是不是有像上面介紹的那么好用。
Java 案例編碼
很簡單的幾個(gè)方法,hotmethod 方法寫了幾個(gè)常見操作,三個(gè)方法中很明顯 hotmethod3 方法里的生成 UUID 和 replace(需要正則匹配)操作消耗的 CPU 性能會(huì)較多。allocate 方法里因?yàn)橐粩嗟膭?chuàng)建長度為 6萬的數(shù)組,消耗的內(nèi)存空間一定是最多的。
import?java.util.ArrayList; import?java.util.Random; import?java.util.UUID;/***?<p>*?模擬熱點(diǎn)代碼**?@Author?niujinpeng*/ public?class?HotCode?{private?static?volatile?int?value;private?static?Object?array;public?static?void?main(String[]?args)?{while?(true)?{hotmethod1();hotmethod2();hotmethod3();allocate();}}/***?生成?6萬長度的數(shù)組*/private?static?void?allocate()?{array?=?new?int[6?*?1000];array?=?new?Integer[6?*?1000];}/***?生成一個(gè)UUID*/private?static?void?hotmethod3()?{ArrayList<String>?list?=?new?ArrayList<>();UUID?uuid?=?UUID.randomUUID();String?str?=?uuid.toString().replace("-",?"");list.add(str);}/***?數(shù)字累加*/private?static?void?hotmethod2()?{value++;}/***?生成一個(gè)隨機(jī)數(shù)*/private?static?void?hotmethod1()?{Random?random?=?new?Random();int?anInt?=?random.nextInt();} }CPU 性能分析
運(yùn)行上面的程序,然后使用 JPS 命令查看 PID 信息。
???develop?jps 2800?Jps 2449?HotCode 2450?Launcher 805?RemoteMavenServer36 470?NutstoreGUI 699 ???develop上面運(yùn)行的類名是 HotCode,可以看到對應(yīng)的 PID 是 2449。
使用?./profiler.sh -d 20 -f 2449.svg 2449?命令對 2449 號進(jìn)程采樣20秒,然后得到生成的 2449.svg 文件,然后我們使用瀏覽器打開這個(gè)文件,可以看到 CPU 的使用火焰圖。
CPU 使用火焰圖關(guān)于火焰圖怎么看,一言以蔽之:火焰圖里,橫條越長,代表使用的越多,從下到上是調(diào)用堆棧信息。在這個(gè)圖里可以看到 main 方法上面的調(diào)用中 hotmethod3 方法的 CPU 使用是最多的,點(diǎn)擊這個(gè)方法。還可能看到更詳細(xì)的信息。
hotmethod3 CPU 火焰圖可以看到 replace 方法占用的 CPU 最多,也是程序中性能問題所在,是需要注意的地方。
Heap 內(nèi)存分析
還是上面運(yùn)行的程序,進(jìn)程 PID 還是 2449,這次使用 -e 參數(shù)分析內(nèi)存使用情況。
命令:./profiler.sh -d 20 -e alloc -f 2449-alloc.svg 2449
命令的意思是收集進(jìn)程號是 2449 的進(jìn)程的內(nèi)存信息 20 秒,然后輸出為 2449-alloc.svg 文件。20秒后得到 svg 文件使用瀏覽器打開,可以看到內(nèi)存分配情況。
內(nèi)存分配火焰圖依舊是橫條越長,代表使用的越多,從下到上是調(diào)用堆棧信息。從圖里可以看出來 main 方法調(diào)用的 allocate 方法使用的內(nèi)存最多,這個(gè)方法里的 Integer 類型數(shù)組占用的內(nèi)存又最多,為 71%。
有道無術(shù),術(shù)可成;有術(shù)無道,止于術(shù)
歡迎大家關(guān)注Java之道公眾號
好文章,我在看??
總結(jié)
以上是生活随笔為你收集整理的超好用的自带火焰图的 Java 性能分析工具 Async-profiler 了解一下的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: NYOJ 594 还是A+B
- 下一篇: 面试官,求求你不要问我这么简单但又刁难的