小程序使用async_使用Async Profiler对Java应用程序进行性能分析

小程序使用async

免责声明:该故事并非由Async Profiler赞助。

总览

大多数Java采样分析器都依靠“ Java虚拟机工具接口(JVM TI) ”来分析Java应用程序。 但是,JVM TI有一个固有的局限性。 JVM TI仅允许在安全点收集堆栈跟踪。 因此,任何使用JVM TI的采样分析器都存在安全点偏差问题。

Async Profiler ”不使用JVMTI来获取堆栈跟踪样本,因此避免了安全点偏差问题。 让我们首先了解这个问题。

那么,什么是安全点?

“安全点是时刻,线程的数据,内部状态和在JVM中的表示很安全,可以被JVM中的其他线程观察。”

以下是Java应用程序中安全点的一些示例。

  1. 每2个字节码之间(解释器模式)
  2. 非计数循环的后端
  3. 方法退出
  4. JNI呼叫退出

安全点偏差问题

Nitsan Wakart在许多地方都谈到了这个安全点偏差问题。 他的博客文章“ 为什么(大多数)采样Java Profiler如此糟糕 ”,可能是描述此问题的最全面的博客文章。

总而言之,当采样探查器获得样本堆栈跟踪时,应用程序线程将停止以收集数据,并且线程将恢复。 这里的问题是,应用程序线程仅在安全点处停止,因此,当探查器以预定的时间间隔获取堆栈跟踪样本时,仅在下一个可用的安全点轮询位置检索堆栈跟踪。 因此,样本偏向安全点,分析器可能报告不准确的数据。

我们如何避免这种安全点偏差问题?

有一个AsyncGetCallTrace方法,它是一个OpenJDK内部API调用,用于促进非安全点收集堆栈跟踪。 有一些分析器使用此AsyncGetCallTrace方法来避免安全点偏差问题

Nitsan还在AsyncGetCallTrace方法上写了一篇很棒的博客文章:“ AsyncGetCallTrace Profilers的优缺点

诚实剖析器 ”是第一个没有安全点偏差问题的Java采样剖析器。 Honest Profiler拥有自己的采样代理 ,该代理使用UNIX操作系统信号和AsyncGetCallTrace API来高效,准确地分析Java应用程序。

Java Flight Recorder也不要求线程处于安全点才能对堆栈进行采样。 但是,如果不使用以下标志,它将无法获取代码中非安全点部分的元数据:“ -XX:+UnlockDiagnosticVMOptions -XX:+DebugNonSafepoints

异步探查器简介

现在,您必须已经弄清楚“ Async Profiler ”还通过使用AsyncGetCallTrace API避免了安全点偏差问题。

异步探查器 是Java的低开销采样分析器。 它结合使用AsyncGetCallTraceperf_events来提供应用程序的更整体视图,包括系统代码路径和Java代码路径。 异步事件探查器可与任何基于HotSpot JVM(具有AsyncGetCallTrace方法)的JDK配合使用,例如OpenJDK和Oracle JDK。

使用perf_events ,可以分析应用程序的系统代码路径。 Async Profiler很好地结合了来自perf_events系统代码路径和来自AsyncGetCallTrace API的Java代码路径。

在使用Async Profiler进行性能分析时,还建议使用以下标志:“ -XX:+UnlockDiagnosticVMOptions -XX:+DebugNonSafepoints

异步事件探查器支持多种类型的分析。 例如,

  1. CPU分析
  2. 分配分析
  3. 挂钟分析
  4. 锁分析

Async Profiler的另一个激动人心的功能是开箱即用的火焰图支持,它可以可视化堆栈跟踪。

Flame Graph只是Async Profiler支持的输出格式之一。 有趣的是,Async Profiler还可以通过“方法配置样本”事件来生成Java飞行记录

以下是Async Profiler支持的输出类型。

  1. 摘要 :执行概要摘要
  2. traces :以样本计数的降序列出所有唯一的堆栈跟踪样本。
  3. flat :列出堆栈跟踪样本中的所有顶级方法。
  4. 折叠 :折叠的堆栈跟踪输出与Brendan Gregg的flamegraph.pl脚本兼容。
  5. svg :将所有堆栈轨迹可视化为火焰图。
  6. tree :Web(HTML)页面,将所有堆栈跟踪显示为调用树。
  7. jfr :带有方法概要分析样本事件的Java飞行记录

最后三个输出( svgtreejfr )应与将输出转储到文件的选项一起使用。

如果输出文件具有*.svg*.html*.jfr扩展名,则输出格式将分别自动为svgtreejfr

summarytracesflat输出可以组合。 这实际上是Async Profiler的默认输出。

异步事件探查器入门

如前所述,Async Profiler依赖于perf_events 。 应该执行以下配置以使用来自非根进程的perf_events捕获内核调用堆栈。

  1. /proc/sys/kernel/perf_event_paranoid1
  2. /proc/sys/kernel/kptr_restrict0

第一个设置将允许一般用户分析内核。 第二个设置将禁用对公开内核地址的限制。

您可以将值直接写入提到的文件,也可以使用sysctl命令更新值。

写入文件:

echo 1 | sudo tee /proc/sys/kernel/perf_event_paranoid
echo 0 | sudo tee /proc/sys/kernel/kptr_restrict

使用sysctl命令:

sudo sysctl -w kernel.perf_event_paranoid=1
sudo sysctl -w kernel.kptr_restrict=0

您也可以在/etc/sysctl.conf中添加以下行,以使设置永久化。 ( 通常不建议这样做

kernel.perf_event_paranoid =1
kernel. kptr_restrict =0

可以从GitHub版本页面下载最新的Async Profiler,或者您可以轻松构建Async Profiler。 异步分析器也包含在IntelliJ IDEA中

由于我喜欢使用最新的更改,因此我从源代码构建了Async Profiler。 构建探查器很容易。 我刚刚导出了JAVA_HOME并执行了make命令。

让我们对一些示例应用程序进行概要分析,并查看每个概要文件的外观。

我使用开发的示例应用程序来演示各种性能问题。 源代码位于https://github.com/chrishantha/sample-java-programs/

我将使用svg输出,因为使用Flame Graph可视化堆栈跟踪更加容易。

CPU分析

为了分析CPU,我使用了“ highcpu ”示例应用程序。 该应用程序具有多个线程,它们执行一些CPU消耗任务,例如为某些随机UUID计算哈希并执行一些数学运算。

我使用以下命令执行了该应用程序。

java -Xms128m -Xmx128m -XX:+UnlockDiagnosticVMOptions -XX:+DebugNonSafepoints -jar target/highcpu.jar  --exit -timeout 600

在应用程序运行时,我使用以下命令将CPU配置文件占用了30秒。

./profiler.sh -d 30 -f cpu-flame-graph.svg --title"CPU profile" --width 1600 $(pgrep -f highcpu)

以下是火焰图,显示了哪些方法在CPU上。

在这里,我们可以看到Flame Graph同时显示了系统代码路径和Java代码路径。

没有Async Profiler,获得类似的Flame Graph并不容易。 为了生成“ Java混合模式火焰图 ”,必须执行以下步骤。

  1. 使用-XX:+PreserveFramePointer运行应用程序。
  2. 使用perf record命令分析应用程序,并生成一个perf.data文件。
  3. 使用perf-map-agent生成Java符号表,以将Java代码地址映射到方法名称。
  4. 使用perf script命令,获取折叠输出,并生成Flame Graph。

这种方法有很多问题。 例如, -XX:+PreserveFramePointer标志(仅在JDK 8u60及更高版本中可用)会产生性能开销。 有时,由于方法内联,框架将丢失。

分配分析

异步事件探查器还可用于探查分配堆内存的代码。 它使用TLAB (线程本地分配缓冲区)回调,可以在生产中使用它而没有太多开销。 Java Flight Recorder也使用类似的方法。

让我们看一下相同highcpu示例应用程序的分配配置文件。 请注意,分析事件类型为alloc

./profiler.sh -e alloc -d 30 -f alloc-flame-graph.svg --title"Allocation profile" --width 1600 $(pgrep -f highcpu)

现在,顶部边缘显示了分配内存的方法。 在这里,我们可以快速查看哪些代码路径在应用程序中分配内存。

让我们看看另一个名为“ allocations ”的示例应用程序。 此应用程序在有限循环中检查数字是否为质数。

与highcpu应用程序不同,此应用程序会在短时间内终止。 因此,我从一开始就通过将Async Profiler作为代理启动来配置分配。

java -Xms64m -Xmx64m -XX:+UnlockDiagnosticVMOptions -XX:+DebugNonSafepoints -agentpath:"/home/isuru/projects/git-projects/async-profiler/build/libasyncProfiler.so=start,event=alloc,file=allocation-flame-graph.svg,svg,title=Allocation profile,width=1600" -jar target/allocations.jar

以下是火焰图输出。

从“分配火焰图”可以清楚地看到,几乎所有分配都是由于Java自动装箱造成的 ,这在查看代码时不容易理解。

挂钟分析

通过使用wall事件类型,Async Profiler还可同等地对所有线程进行采样,而与每个线程的状态(运行,睡眠或已阻止)无关。

挂钟配置文件对于确定线程随时间的变化非常有用。 挂钟分析可用于解决应用程序启动时间中的问题。

由于所有线程都进行了概要分析,而与线程状态无关,因此Wall-clock概要分析器在每个线程模式下最有用。

让我们来看一个例子。 以下是highcpu应用程序的挂钟简介。

./profiler.sh -e wall -t -d 30 -f wall-flame-graph.svg --title"Wall clock profile" --width 1600 $(pgrep -f highcpu)

火焰图上方显示每个线程的样本数量几乎相等。

让我们看一下“ 延迟 ”应用程序的另一个挂钟配置文件。 该应用程序主要有两个线程(偶数线程和奇数线程)来打印偶数和奇数。 检查数字是否为偶数的方法已同步。

java -Xms64m -Xmx64m -XX:+UnlockDiagnosticVMOptions -XX:+DebugNonSafepoints -XX:+UseSerialGC -agentpath:"/home/isuru/projects/git-projects/async-profiler/build/libasyncProfiler.so=start,event=wall,file=wall-flame-graph.svg,threads,svg,simple,title=Wall clock profile,width=1600" -jar target/latencies.jar --count 10

火焰图上方清楚地显示了所有线程的线程状态。 偶数和奇数线程大部分时间处于“睡眠”或“阻塞”状态。

锁分析

可以使用Async Profiler中的lock事件类型来分析Java应用程序中的lock

让我们看一下“延迟”应用程序的锁定配置文件。

java -Xms64m -Xmx64m -XX:+UnlockDiagnosticVMOptions -XX:+DebugNonSafepoints -XX:+UseSerialGC -agentpath:"/home/isuru/projects/git-projects/async-profiler/build/libasyncProfiler.so=start,event=lock,file=lock-flame-graph.svg,svg,simple,title=Lock profile,width=1600" -jar target/latencies.jar --count 10

火焰图上方显示了由于锁定而阻塞的代码路径。

其他类型的剖析

异步事件探查器还具有许多其他事件类型。 例如,它支持perf_events一些硬件和软件性能计数器。

这意味着,使用Async Profiler,可以轻松地对诸如context-switchespage-faults等软件性能计数器以及诸如cache-missesbranch-misses等硬件性能计数器进行分析。

要查看目标JVM支持的所有事件类型,可以使用list操作。

./profiler.sh list jps
Basic events:
  cpu
  alloc
  lock
  wall
  itimer
Perf events:
  page-faults
  context-switches
  cycles
  instructions
  cache-references
  cache-misses
  branches
  branch-misses
  bus-cycles
  L1-dcache-load-misses
  LLC-load-misses
  dTLB-load-misses
  mem:breakpoint
  trace:tracepoint

摘要

到目前为止,Async Profiler可能是最好的性能分析工具。 它避免了安全点偏差问题,并结合了perf_events的Linux内核配置文件的功能。

Async Profiler支持许多事件,例如CPU周期,Linux性能计数器,分配,锁定尝试等。此故事演示了使用一些示例Java应用程序并生成Flame Graph的Async Profiler的一些示例。

使用Async Profiler真的很容易,尤其是因为它的输出要简单得多,并且不需要特殊的应用程序来处理输出。

我建议您尝试使用Async Profiler,并确保在开发过程中始终对应用程序进行配置(以避免将来产生昂贵的生产问题)。

翻译自: https://hackernoon.com/profiling-java-applications-with-async-profiler-049s2790

小程序使用async

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值