https://github.com/jvm-profiling-tools/honest-profiler
背景
使用 profiler 进行 Java 性能分析的时候,占用时间最长的是 epollWait,据说是 profiler 本身抽样的时候的问题(这个回头再搞清楚具体原因)。
所以使用 honest-profiler,即 hprofiler
编译打包过程
https://github.com/jvm-profiling-tools/honest-profiler/wiki/How-to-build
使用Ubuntu系统,因为MacOS安装cmake时报错了。
- 安装cmake等
sudo apt-get install cmake libunittest++-dev maven pkg-config
- 下载源码
git clone https://github.com/jvm-profiling-tools/honest-profiler.git
- 编译
cd honest-profiler
cmake CMakeLists.txt
export LC_ALL=C
这时候遇到了下面的错误:
Could NOT find JNI (missing: JAVA_AWT_INCLUDE_PATH)
网上查一种说法是要加上环境变量 JAVA_HOME,但是不生效,另外就是在 CMakeLists.txt 里加上一个配置,如下:
...
set(JAVA_AWT_INCLUDE_PATH NotNeeded)
find_package(JNI REQUIRED)
...
可以成功编译了
- 打包
mvn clean package -DskipTests
这个命令又出问题了,找不到 javafx.util 这个包。
查到:https://stackoverflow.com/questions/19015731/javafx-project-doesnt-compile-with-maven
意思是在 pom.xml 里增加一个依赖
com.oracle
javaFX
2.2
system
/path/to/jfxrt.jar
但是这个 jfxrt.jar 包Ubuntu环境里并没有,然后想到从 macOS 环境里找到这个 jfxrt.jar 包,放到Ubuntu里,编译成功。
使用
https://github.com/jvm-profiling-tools/honest-profiler/wiki/How-to-Run
打包成功后在 target 目录里会生成一个 zip 包,解压后,包含了 liblagent.so 的文件,这个是生成hprof是需要的
java -agentpath:/path/to/location/liblagent.so=interval=7,logPath=/path/to/output/log.hpl
java -agentpath:/usr/local/lib64/libhonest-prof.so=interval=7,logPath="/tmp/xxx.hprof" -jar xxx
运行 gui 遇到的问题
- 加载不了 JavaFXApplication
Error: Could not find or load main class com.insightfullogic.honest_profiler.ports.javafx.JavaFXApplication
哪怕安装了 openjfx 和 libopenjfx-jni 都不行,考虑到刚才我们添加了一个 jfxrt.jar 包,可能跟 JavaFXApplication有关,所以再在 classpath 里添加一下试试:
$ cat gui
#!/bin/sh
set -eu
java_path=$(readlink -f $(which javac))
[ -f /usr/libexec/java_home ] && java_home=`/usr/libexec/java_home` || java_home=$(echo ${java_path} | sed 's/javac$//')
tools_path="$java_home/../lib/tools.jar"
[ -f ${tools_path} ] || tools_path="$java_home/lib/tools.jar"
[ -f ${tools_path} ] || (echo "Could not find tools.jar at $java_home/../lib/tools.jar" && exit 1)
java -cp $tools_path:honest-profiler.jar:~/Downloads/jfxrt.jar com.insightfullogic.honest_profiler.ports.javafx.JavaFXApplication
但是依然出错:
GLFactory.static - Platform: Linux - not available: com.sun.prism.es2.X11GLFactory
java.lang.ClassNotFoundException: com.sun.prism.es2.X11GLFactory
at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:264)
at com.sun.prism.es2.GLFactory$FactoryLoader.run(GLFactory.java:108)
at com.sun.prism.es2.GLFactory$FactoryLoader.run(GLFactory.java:100)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.prism.es2.GLFactory.(GLFactory.java:97)
at com.sun.prism.es2.ES2Pipeline.(ES2Pipeline.java:76)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:264)
at com.sun.prism.GraphicsPipeline.createPipeline(GraphicsPipeline.java:187)
at com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.init(QuantumRenderer.java:91)
at com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run(QuantumRenderer.java:124)
at java.lang.Thread.run(Thread.java:748)
java.lang.ClassNotFoundException: com.sun.glass.ui.gtk.GtkPlatformFactory
at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:264)
at com.sun.glass.ui.PlatformFactory.getPlatformFactory(PlatformFactory.java:42)
at com.sun.glass.ui.Application.run(Application.java:146)
at com.sun.javafx.tk.quantum.QuantumToolkit.startup(QuantumToolkit.java:257)
at com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:211)
at com.sun.javafx.application.LauncherImpl.startToolkit(LauncherImpl.java:675)
at com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:337)
at com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:328)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:767)
Failed to load Glass factory class
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:767)
Caused by: java.lang.NullPointerException
at com.sun.glass.ui.Application.run(Application.java:146)
at com.sun.javafx.tk.quantum.QuantumToolkit.startup(QuantumToolkit.java:257)
at com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:211)
at com.sun.javafx.application.LauncherImpl.startToolkit(LauncherImpl.java:675)
at com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:337)
at com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:328)
... 5 more
- 把 zip 包放到 macOS 下,遇到了 readlink 的错误
➜ honest-profiler ./gui
readlink: illegal option -- f
usage: readlink [-n] [file ...]
这其实就是 Linux 系统和 Max OS 系统命令参数不同导致的。比如 date 也是。
直接把 -f 改成 -n 即可。
打开后效果如下:
总结
这次使用 honest-profiler 很是曲折,先是在macOS下编译,发现需要cmake,结果安装不上,在Ubuntu下编译、打包又遇到了很多问题,最终使用时又迁移到macOS系统下。。。
但是还是很值得的,这个 honest-profiler 相比于普通的 profiler,功能还是更加强大一些、关键也更准确一些。
https://web.archive.org/web/20190504151711/http://www.brendangregg.com/blog/2014-06-09/java-cpu-sampling-using-hprof.html
下一篇,记录一次Java性能优化,使用到了 jstat、iostat、profiler以及这个 honest-profiler。