Async-profiler 简介
1. 概述
Java 采样分析器 通常使用 JVM 工具接口 (JVMTI) 设计,并在安全点收集堆栈跟踪。因此,这些采样分析器可能会遇到安全点偏差问题 。
对于应用程序的整体视图,我们需要一个采样分析器,它不需要线程处于安全点,并且可以随时收集堆栈跟踪以避免安全点偏差问题。
在本教程中,我们将探索async-profiler 以及它提供的各种分析技术。
2. async-profiler
async-profiler是基于HotSpot JVM 的任何 JDK 的采样分析器。它的开销很低,并且不依赖于 JVMTI。
它通过使用 HotSpot JVM 提供的AsyncGetCallTrace API 来分析 Java 代码路径,并使用 Linux 的perf_events来分析本机代码路径,从而避免了安全点偏差问题。
换句话说,分析器匹配 Java 代码和本机代码路径的调用堆栈以产生准确的结果。
3. 设置
3.1. 安装
首先,我们将根据我们的平台下载最新版本的async-profiler 。目前,它仅支持 Linux 和 macOS 平台。
下载后,我们可以检查它是否在我们的平台上运行:
$ ./profiler.sh --version
Async-profiler 1.7.1 built on May 14 2020
Copyright 2016-2020 Andrei Pangin
事先检查async-profiler可用的所有选项总是一个好主意:
$ ./profiler.sh
Usage: ./profiler.sh [action] [options]
Actions:
start start profiling and return immediately
resume resume profiling without resetting collected data
stop stop profiling
check check if the specified profiling event is available
status print profiling status
list list profiling events supported by the target JVM
collect collect profile for the specified period of time
and then stop (default action)
Options:
-e event profiling event: cpu|alloc|lock|cache-misses etc.
-d duration run profiling for seconds
-f filename dump output to
-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
-I include output only stack traces containing the specified pattern
-X exclude exclude stack traces with the specified pattern
-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
--cstack mode how to traverse C stack: fp|lbr|no
is a numeric process ID of the target JVM
or 'jps' keyword to find running JVM automatically
许多显示的选项将在后面的部分中派上用场。
3.2. 内核配置
在 Linux 平台上使用async-profiler时,我们应该确保配置我们的内核以使用perf_events捕获所有用户的调用堆栈:
首先,我们将perf_event_paranoid设置为 1,这将允许分析器收集性能信息:
$ sudo sh -c 'echo 1 >/proc/sys/kernel/perf_event_paranoid'
然后,我们将kptr_restrict设置为 0 以消除对公开内核地址的限制:
$ sudo sh -c 'echo 0 >/proc/sys/kernel/kptr_restrict'
但是,async-profiler将在 macOS 平台上自行运行。
现在我们的平台已经准备就绪,我们可以构建我们的分析应用程序并使用 Java 命令运行它:
$ java -XX:+UnlockDiagnosticVMOptions -XX:+DebugNonSafepoints -jar path-to-jar-file
在这里,我们使用-XX:+UnlockDiagnosticVMOptions -XX:+DebugNonSafepoints JVM 标志启动了我们的分析应用程序,强烈建议使用这些标志来获得准确的结果**。
现在我们已经准备好分析我们的应用程序,让我们探索async-profiler支持的各种类型的分析。
4. CPU 分析
Async-profiler在分析 CPU 时收集 Java 方法的样本堆栈跟踪,包括 JVM 代码、本机类和内核函数。 让我们使用它的 PID 来分析我们的应用程序:
$ ./profiler.sh -e cpu -d 30 -o summary 66959
Started [cpu] profiling
--- Execution profile ---
Total samples : 28
Frame buffer usage : 0.069%
在这里,我们使用*-e选项定义了cpu分析事件。然后,我们使用-d duration*选项收集样本 30 秒。
最后,-o选项可用于定义输出格式,如摘要、HTML、跟踪、SVG 和树。
让我们在 CPU 分析我们的应用程序时创建 HTML 输出:
$ ./profiler.sh -e cpu -d 30 -f cpu_profile.html 66959
在这里,我们可以看到 HTML 输出允许我们展开、折叠和搜索示例。
此外,async-profiler支持开箱即用的火焰图。
让我们使用应用程序的 CPU 配置文件的*.svg*文件扩展名生成火焰图:
$ ./profiler.sh -e cpu -d 30 -f cpu_profile.svg 66959
在这里,生成的火焰图以绿色显示 Java 代码路径,黄色显示 C++,红色显示系统代码路径。
5. 分配分析
同样,我们可以收集内存分配样本,而无需使用像字节码检测这样的侵入性技术。
async-profiler使用基于TLAB (线程本地分配缓冲区)的采样技术来收集高于 TLAB 平均大小的堆分配样本。
通过使用alloc事件,我们可以让分析器收集分析应用程序的堆分配:
$ ./profiler.sh -e alloc -d 30 -f alloc_profile.svg 66255
在这里,我们可以看到对象克隆分配了很大一部分内存,否则在查看代码时很难察觉。
6. 挂钟分析
此外,async-profiler可以通过使用挂钟配置文件对所有线程进行采样,而不管它们的状态如何——例如运行、睡眠或阻塞。
在解决应用程序启动时间的问题时,这可以证明很方便。
通过定义wall事件,我们可以配置分析器来收集所有线程的样本:
$ ./profiler.sh -e wall -t -d 30 -f wall_clock_profile.svg 66959
在这里,我们通过使用*-t*选项在每线程模式下使用挂钟分析器,强烈建议在分析所有线程时使用该选项。
此外,我们可以使用list选项检查 JVM 支持的所有分析事件:
$ ./profiler.sh list 66959
Basic events:
cpu
alloc
lock
wall
itimer
Java method calls:
ClassName.methodName
7. 使用 IntelliJ IDEA的 async-profiler
IntelliJ IDEA 集成了async-profiler作为 Java 的分析工具。
7.1. 探查器配置
我们可以通过在Settings/Preferences > Build, Execution, Deployment中选择Java Profiler菜单选项来在 IntelliJ IDEA中配置async-profiler :
此外,为了快速使用,我们可以选择任何预定义的配置,例如 IntelliJ IDEA 提供的 CPU Profiler 和 Allocation Profiler。
同样,我们可以复制分析器模板并编辑特定用例的代理选项。
7.2. 使用 IntelliJ IDEA 的配置文件应用程序
有几种方法可以使用分析器分析我们的应用程序。
例如,我们可以选择应用程序并选择*Run with *选项:
或者,我们可以单击工具栏并选择*Run with *选项:
或者,通过选择Run菜单下的**Run with Profiler选项,然后选择 < profiler configuration name>:
此外,我们可以在Run菜单下看到*将 Profiler 附加到 Process的选项。*它会打开一个对话框,让我们选择要附加的进程:
分析我们的应用程序后,我们可以使用IDE 底部的Profiler工具窗口栏分析分析结果。
我们应用程序的分析结果将如下所示:
它以不同的输出格式显示线程明智的结果,如火焰图、调用树和方法列表。
或者,我们可以选择View > Tool Windows**菜单下的Profiler选项来查看结果: