限时领|《AI 百问百答》专栏课+实体书(包邮)! 了解详情
写点什么

开源 Java 性能分析器比较:VisualVM、JMC 和 async-profiler

作者:Johannes Bechberger

  • 2023-06-28
    北京
  • 本文字数:4534 字

    阅读完需:约 15 分钟

开源Java性能分析器比较:VisualVM、JMC和async-profiler

在本文中,我将介绍性能分析的基本概念和不同类型的开源 Java 分析器,让你可以根据自己的需要选择最适合的分析器,并了解这些工具大致的工作原理。

 

2023年伦敦QCon演讲“你的Java应用程序很慢吗?试试这些开源分析器”中,我深入探讨过这个话题,也介绍了不同的性能查看器。本文是基于那次演讲整理而成。

 

分析器的目的是获取有关程序执行的信息,让开发人员可以看到一个方法在给定的时间段内执行了多长时间。

 

但它们是如何做到这一点的呢?有两种方法:程序插桩和抽样。

 

插桩分析器

 

获取性能分析概要的一种方法是,对于开发人员感兴趣的每个方法,记录其进入和退出时间。

 

当想要知道程序的特定部分花费了多长时间时,许多开发人员都会使用这种检测方法。

 

在这种方法中,下面的方法:

 

void methodA() {      // … // 做工作}
复制代码

 

会被修改成:

 

void methodA() {      long start = System.currentTimeMillis();      // … // 做工作      long duration = System.currentTimeMillis() - start;      System.out.println(“methodA took “ + duration + “ms”);}
复制代码

 

这种修改可以用于基本的时间测量。尽管如此,在嵌套测量方法时,它提供的信息很少,因为了解方法之间的关系也很有趣,例如methodB()methodA()在几秒钟内执行。因此,我们需要记录每次进入和退出相关方法的日志。这些日志会关联到时间戳和当前线程。

 

插桩分析器的思想是将这种代码修改的过程自动化:它将logEntry()logExit()方法的调用插入到方法的字节码中。这些方法是分析器运行时库的一部分。通常,这种插入是在运行时完成的,即在类加载时通过插桩代理完成。然后,分析器将methodA()修改为:

 

void methodA() {      logEntry(“methodA”);      // … // 做工作      logExit(“methodA”);}
复制代码

 

插桩分析器的优点是它们对所有 JVM 都有效,因为它们可以用纯 Java 实现。但它们有一个缺点,即插入的方法调用会导致显著的性能损失并严重影响结果。因此,在最近几十年里,纯插桩分析器的流行度已然消退。如今,现代分析器大多都是抽样分析器。

 

抽样分析器

 

另一种分析器是抽样分析器,它们会在被分析程序执行时进行抽样。这类分析器会定期向 JVM 请求当前运行程序的堆栈,通常是每 10 毫秒到 20 毫秒一次。然后,分析器会使用这些信息来估算性能。这种方法的主要缺点是:运行时间比较短的方法可能不会在性能分析概要中出现。

 

抽样分析器的主要优点是:它们不会修改程序,开销比较小,不会对结果产生明显的影响。

 

现代抽样分析器通常每 10 到 20 毫秒一次循环运行以下代码:



抽样分析器每次迭代都会获取当前的(Java)线程列表。然后,它会随机选择一个线程子集进行抽样。通常,这个子集的大小在 5 到 8 之间,因为每次迭代对太多线程进行抽样会增加运行分析器的性能影响。在分析具有大量线程的应用程序时,请注意这一点。

 

然后,分析器向每个选定的线程发送一个信号,这将导致它们停下来调用信号处理程序。此信号处理程序会获取并存储其线程的堆栈跟踪。在每次迭代结束时,分析器会收集所有堆栈跟踪信息并进行后处理。

 

实现抽样分析器还有其他的方法,但我这里介绍的是使用最广泛且精度最佳的技术。

 

不同的开源分析器

 

目前,最著名的开源分析器有 3 个:VisualVM、async-profiler 和 JDK Flight Recorder(JFR)。这些分析器都处于积极开发过程中,可用于各种应用程序。它们都是抽样分析器。VisualVM 是唯一支持插桩分析的分析器。

 


我们可以区分下“外部”和“内置”分析器:外部分析器不是直接实现到 JVM 中,而是使用 API 来收集特定线程的堆栈跟踪信息。对于只使用 API 的分析器,同一个版本可以用于不同的 JVM 版本和供应商(如 OpenJDK 和 OpenJ9)。

 

最著名的外部分析器有两个:VisualVM 和 async-profiler;它们的主要区别在于它们使用的 API。VisualVM 使用官方的Java管理扩展(JMX)来获取线程的堆栈跟踪信息。另一方面,async-profiler 使用非官方的 AsyncGetCallTrace API。两者各有优缺点,但通常,JMX 及相关 API 被认为更安全,而 AsyncGetCallTrace 更精确。

 

OpenJDK 和 GraalVM 仅有一个内置分析器 Java Flight Recorder(JFR);它的工作原理与 async-profiler 大致相同,同样精确,但更稳定。

 

接下来,我将介绍这几个分析器及其历史。

 

VisualVM

 

该工具是 Netbeans 分析器的独立版本。从 2006 年的 Oracle JDK 6 到 JDK 8,每个 JDK 都包含 Java VisualVM 工具。该工具于2008年开源。后来,这个分析器更名为 VisualVM,Oracle JDK 9 不再包含它。根据JetBrains最近的一项调查,VisualVM 是最常用的开源分析器。需要的话,可以从这里下载。

 

它的用法很简单;只需要在 GUI 中为你想要分析的程序选择运行它的 JVM 并启动性能分析:



然后,你可以在一个简单的树形可视化中直接查看性能分析概要信息。也可以从命令行启动和停止抽样分析器:

 

visualvm --start-cpu-sampler <pid>visualvm --stop-sampler <pid>
复制代码

 

VisualVM 提供了易于使用的简单 UI,但需要注意,它使用了不太精确的 JVM API。

 

Async-Profiler

 

Async-profiler 是最常用的分析器之一,这不仅仅是因为它被嵌入到了许多其他工具中,如 IntelliJ Ultimate Profiler 和 AppIication Performance Monitors。你可以从项目的GitHub页面下载 async-profiler。它包含特定于平台的二进制文件,不支持 Windows。因此,我创建了app-loader项目,将所有 async-profiler 二进制文件封装到一个多平台二进制文件中,使得嵌入并使用这个分析器变得更容易。

 

你可以通过许多嵌入了 async-profiler 的工具使用它,或直接将其作为本机 Java 代理来使用。假设你下载了特定于平台的 libasyncProfiler.so,则只需在调用 Java 二进制文件时添加以下选项,即可分析 Java 应用程序的性能:

 

java -agentpath:libasyncProfiler.so=start,event=cpu,file=flame.html,flamegraph …
复制代码

 

这个调用告诉 async-profiler 生成一个火焰图。这是一种非常流行的可视化方式。

 

你也可以用它创建 JFR 文件:

 

java -agentpath:libasyncProfiler.so=start,event=cpu,file=profile.jfr,jfr …
复制代码

 

这个调用让你可以在众多查看器中查看性能分析概要文件。

 

以下是 async-profiler 的发展简史,感兴趣的可以了解一下。

 

2002 年 11 月,Sun(后来被 Oracle 收购)根据JVM(TM)工具接口规范将 AsyncGetStackTrace API 添加到 JDK 中。新 API 使得从外部分析器获得精确的堆栈跟踪信息成为可能。Sun 引入这个 API 是为了给他们的 Sun Development Studio 添加一个完整的 Java 分析器。然而,两个月后,他们删除了该 API,原因未公开。但是,这个 API 仍然以 AsyncGetCallTrace 的形式保留在 JDK 中,直到今天一直存在,只是没有导出,所以比较难用。

 

几年后,人们偶然发现,这个 API 是一个不错的实现分析器的方法。2007 年,Jeremy Manson 在博文“使用JVMTI/JVMPI、SIGPROF和AsyncGetCallTrace进行性能分析”中,首次提到将 AsyncGetCallTrace 作为实现 Java 分析器的基础。从那时起,许多开源和闭源分析器就开始使用它。YourKitJProfilerhonest-profiler是其中几个比较有名的例子。Async-profiler 的开发始于 2016 年;它目前是使用 AsyncGetCallTrace 的最主要的开源分析器。

 

Async-profiler 的问题在于,它是基于一个非官方的内部 API。这个 API 没有经过官方 OpenJDK 测试套件的充分测试,随时都可能失效。尽管该 API 的广泛应用使得它已近乎标准化,但这仍然是一个风险。为了减轻这些风险,我目前正在编制一份 JDK 增强提案,在 OpenJDK 中增加一个官方的 AsyncGetCallTrace 版本;见JEP候选435

 

Async-profiler 的优势在于它的许多特性(如堆采样)、可嵌入性、对其他 JVM(如 OpenJ9)的支持,以及它小巧的代码库,这使得它的适应性非常好。要了解关于 async-profiler 的更多信息,可以查看async-profiler自述文件async-profiler维基以及 Krzysztof Ślusarski 提供的async-profiler实用手册

 

JDK Flight Recorder(JFR)

 

JRockit 最初开发运行时分析器是为了内部使用,但它也越来越受应用程序开发人员的欢迎。后来,在 Oracle 收购了其开发公司之后,这些特性被集成到了 Oracle JDK 中。最终,Oracle 将该工具与 JDK11 一起开源,从那时起,它就成了 OpenJDK JVM 的内置分析工具,不再支持 OpenJ9 等其他 JVM 了。

 

它的工作原理与 async-profiler 类似,主要区别是它直接使用内部的 JVM API。该分析器的使用很简单,可以通过在 Java 二进制文件的调用中添加以下选项:

 

$ java \  -XX:+UnlockDiagnosticVMOptions \  -XX:+DebugNonSafepoints \  # improves precision  -XX:+FlightRecorder \  -XX:StartFlightRecording=filename=file.jfr \  arguments
复制代码

 

或者使用 JDK 命令行工具jcmd 启动和禁用它:

 

$ jcmd PID JFR.start$ jcmd PID JFR.dump filename=file.jfr$ jcmd PID JFR.stop
复制代码

 

JFR 捕获许多性能分析事件,从堆栈跟踪信息抽样到垃圾收集和类加载统计信息。JFR事件网站上提供了所有事件的列表。我们甚至还可以添加自定义事件

 

要了解更多关于这个工具的信息,可以阅读JDK Flight Recorder、The Programmatic Way(来自 BellSoft)等博客的文章。

 

与 async-profiler 相比,JFR 的主要优势是它存在于所有平台的 OpenJDK 中,甚至在 Windows 上。此外,JFR 更稳定一些,记录的事件和信息也更多。JFR 有一个名为 JDK 任务控制的 GUI,它让你可以分析 JVM 性能并查看生成的 JFR 性能分析概要。

 

正确性与稳定性

 

在使用我所介绍的分析器时,务请记住以下内容:它们本身也是软件,与大型项目 OpenJDK(或 OpenJ9)交织在一起,因此,它们也会遇到与它们所分析应用程序相同的典型问题:

  • 测试可以更丰富,特别是底层 API,可以更好地测试一下;目前只有一个测试。(我正在努力)

  • 测试可以做得更好:现有的测试甚至没有充分测试 API 是否适用于小样本。它只检查了最上面的帧,但忽略了返回的跟踪信息太短这个问题。我发现了这个问题并修复了测试用例。

  • 缺乏自动化回归测试:缺乏测试还意味着,对当前项目中看似不相关部分的更改可能会对分析产生不利的影响,而又没有人注意到。

 

因此,对于分析器生成的性能分析概要,你要持保留态度。以下博文和演讲谈及了分析器的准确性问题:

 

此外,在极少数情况下,对应用程序进行性能分析还可能导致 JVM 崩溃。像Jaroslav Bachorik这样的 OpenJDK 开发人员正设法尽可能地修复底层分析 API 中存在的所有稳定性问题。在实践中,使用上面提到的任何一种分析器都是安全的,很少会引发崩溃。如果遇到问题,请联系分析程序开发人员或在相应的存储库中开一个 GitHub 问题。

 

小结


现代基于抽样的 Java 分析器使得使用开源工具调查性能问题成为可能。你可以选择:

  • 一个稍微有点不精确但易于使用并且提供了简单 UI 的工具(VisualVM)

  • 一个内置的工具,提供包括 GC 信息在内的更多信息(JFR)

  • 一个提供很多选项的工具,可以显示 C/C++代码的信息(async-profiler)

 

都试用一下,以便了解在下一次遇到性能问题时使用哪种工具。

 

原文链接:

https://www.infoq.com/articles/open-source-java-profilers/


相关阅读:

JEP 443:未命名模式和变量致力于提升 Java 代码的可读性

JEP 444:JDK 21 中出现虚拟线程,开创并发新纪元

快速实现不打折扣的云原生 Java 应用

2023-06-28 08:004389

评论 1 条评论

发布
用户头像
线上环境, 使用 async-profiler 很方便
2023-07-28 15:26 · 上海
回复
没有更多了
发现更多内容

协同存储,为边缘计算创造更大价值

阿里云CloudImagine

云计算 边缘计算

如何提升运维的效率,可以用小程序试试

没有用户名丶

pix2pix3D:只需编辑标签,就能生成更逼真的三维图像

Zilliz

2023最新版Java面试八股文大全PDF版限时分享,含700道高频面试题

Java你猿哥

Java ssm Java 面试 面经 春招

树莓派+阿里云IoT人脸识别场景实战——业务系统架构类

阿里云AIoT

Python JavaScript 物联网 对象存储 Web App开发

得物榜单|全链路生产迁移及B/C端数据存储隔离

得物技术

运维 生产

“伯乐”流量调控平台工程视角 | 得物技术

得物技术

运营 架构-

应用内支付服务现网、沙盒环境下常见关键事件的对比与总结

HarmonyOS SDK

HMS Core

强烈推荐!阿里架构师纯手写的大型分布式项目《凤凰架构》手册

Java你猿哥

Java 架构 微服务 微服务架构 面经

火山引擎数智平台VeDI 帮助智能投影仪更懂用户需求

字节跳动数据平台

营销数字化 业务增长 用户运营 企业号 1 月 PK 榜

DNS、硬件、LVS、Nginx该如何搭配?

源字节1号

前端开发 后端开发 小程序开发,软件开发

LED显示屏与LCD拼接屏的对比

Dylan

PC LCD1602液晶显示屏 LED显示屏

在昇腾平台上对TensorFlow网络进行性能调优

华为云开发者联盟

人工智能 华为云 昇腾 华为云开发者联盟 企业号 3 月 PK 榜

火山引擎DataLeap:一家企业,数据体系要怎么搭建?

字节跳动数据平台

大数据 数据架构 数据治理 数据研发 企业号 3 月 PK 榜

NCCL源码解析①:初始化及ncclUniqueId的产生

OneFlow

人工智能 深度学习

深圳高新技术企业申请条件以及流程简单说明

行云管家

高新企业 高新技术 高新

GPT-4问世;LLM训练指南;纯浏览器跑Stable Diffusion

OneFlow

人工智能 深度学习

DockQuery | 成为信创产业“关键码”

BinTools图尔兹

数据库 信创产业 国产数据库工具 DockQuery

IDEA 插件最佳组合:JRebel+XRebel 热部署和接口分析优化,太爽了

Java你猿哥

Java Spring Boot ssm IDEA 热部署

认识一下,我们是应用社交「幕后大佬」 IM 家族

融云 RongCloud

即时通讯 IM

高级数据库管理:SQLPro for SQLite激活版

真大的脸盆

数据库 Mac 数据库管理工具 数据库管理 Mac 软件

【总结】Java实现短信验证码

宙哈哈

Java 验证码

透过现象看Java AIO的本质 | 得物技术

得物技术

后端 Java】

ChunJun 顺利晋级“2022 年中国开源创新大赛”决赛,并荣获“优秀开源项目/社区”奖项

袋鼠云数栈

开源

3 月 16 日晚 8 点,陪你一起从 CentOS 迁移到 OpenCloudOS!

OpenCloudOS

Linux

火山引擎DataTester:A/B实验如何应用在抖音的产品优化流程中?

字节跳动数据平台

大数据 云服务 AB testing实战 ab测试 企业号 3 月 PK 榜

【小程序案例】支付宝小程序-MQTT模器,IoT设备通过WSS接入阿里云IoT物联网平台——设备接入类

阿里云AIoT

JavaScript windows 物联网

行云管家堡垒机客服电话是多少?谁知道?

行云管家

网络安全 数据安全 堡垒机 行云管家

C#滑动拼图验证码实现笔记

宙哈哈

C# html 验证码

LP流动性质押挖矿dapp系统开发分红模式定制

开发v-hkkf5566

狂野之心 The Wild at Heart for Mac (魔法森林冒险游戏)

互联网搬砖工作者

开源Java性能分析器比较:VisualVM、JMC和async-profiler_编程语言_InfoQ精选文章