前言

Github:https://github.com/HealerJean

博客:http://blog.healerjean.com

一、程序性能优化分析

1)分析什么

程序性能优化分析,主要是要找到一段程序中运行时间占用整体时间较长的代码,针对性的进行优化程序逻辑,最终缩短程序的运行时长。基本的核心思想就是在程序开始和结束处记录下开始时间、结束时间,这样就知道程序耗时情况

2)工具比较

工具名称 简介 优点 缺点 适用场景 选择建议 功能特点 定价策略 易用性
JProfiler 专业的 Java 性能分析工具,集成了 CPU、内存和线程分析等功能。 界面友好、支持多种数据视图、与主流 IDE 集成、分析结果准确。 商业软件,费用较高,对新手可能有一定学习曲线。 适用于需要深入分析应用性能的场景,如 CPU 和内存热点分析。 如果需要全面专业的性能分析工具,且预算充足,可选择。 CPU 分析、内存泄漏检测、线程分析、SQL 性能检测等。 提供试用版,正式版需购买许可证。 界面直观,操作便捷,但高级功能需要学习。
Async-profiler 低开销的本地分析器,支持 CPU 和内存的火焰图分析。 低性能开销、精确、高效、支持火焰图、可用于生产环境。 命令行工具,缺乏 GUI 界面,使用需要一定技术基础。 在生产环境中进行低开销的性能分析,尤其适合高并发场景。 如果需要在生产环境进行性能采样,Async-profiler 是优秀选择。 ``CPU 和内存采样、火焰图生成、支持多种 JVM 免费开源。 需要命令行操作,学习曲线较陡。

二、火焰图介绍

1、什么是火焰图?

火焰图(Flame Graph)是一种用于性能分析Profiling)的可视化工具,它以直观、交互式的方式展示程序的调用栈信息和资源消耗(如 CPU 时间、内存、I/O 等)。

它的名字来源于其独特的视觉样式:图形的底部是调用栈的根(如main函数),顶部是叶子函数,每一层代表调用栈的一个层级,函数按字母顺序从左到右排列,形似向上燃烧的火焰。

火焰图是性能分析的利器,它将复杂的调用栈数据转化为易于理解的视觉图形,极大地提高了定位性能问题的效率。掌握火焰图的阅读和生成方法,是现代软件开发者进行性能调优的必备技能之一。其核心思想——“将时间花在哪里”——是性能分析的根本出发点。

2、核心作用

  • 定位性能瓶颈:快速识别消耗最多资源(通常是 CPU 时间)的函数。
  • 理解程序执行路径:清晰地看到函数之间的调用关系和调用栈深度。
  • 分析热点代码:找出“热点”(Hot Spots),即被频繁执行或耗时较长的代码段。
  • 优化代码性能:为代码优化提供数据支持,指导开发者优先优化最耗时的部分。



3、结构与解读

1)理解结构

火焰图就是看顶层的哪个函数占据的宽度最大。只要有”平顶”(plateaus),就表示该函数可能存在性能问题。

  • x 轴表示抽样数,如果一个函数在 x 轴占据的宽度越宽,就表示它被抽到的次数多,即执行的时间长。注意,x 轴不代表时间,而是所有的调用栈合并后,按字母顺序排列的。

  • y 轴表示调用栈,每一层都是一个函数。调用栈越深,火焰就越高,底部是调用栈的起点(如main),向上是逐层的函数调用。一个函数框的高度代表它在调用栈中的层级。

  • 函数框(Frame):每个矩形块代表一个函数。

    • 块的 位置 表示其在调用栈中的位置。
    • 宽度 = 资源消耗(如 CPU 时间)的比例:一个函数框越宽,表示在采样期间,该函数(或其子函数)被调用时所占据的总资源越多。
    • 颜色:通常使用暖色调(如红色、橙色)表示较高的 CPU 活动,冷色调(如蓝色)表示较低的活动。但颜色本身没有严格标准,更多是为了视觉区分。

2)用例分析

image-20251010190539902

a、调用链路

  • a() 是最底层的函数(可能是入口点)。

  • a() 调用了 b()h()(因为它们都在 a() 的正上方,且 b() 在左,h() 在右)。

  • b() 调用了 c()

  • c() 调用了 d()

  • d() 调用了 f()e()

  • f() 调用了 g()

  • i()a() 的另一个分支,与 h() 并列。

b、分析

  1. 首要目标是 g():它是最宽的函数,是最大的性能瓶颈。必须首先调查 g() 函数内部发生了什么。
  2. 次重要目标是 b() 分支a() 调用 b() 的路径非常耗时,这导致了 d()f() 等函数也显得很宽。需要深入调查 b() 分支的代码逻辑,特别是 c()d()f()g() 的实现。
  3. d() 的宽度大,但根源在下方:不要只盯着 d(),要向下追溯到 f()g()
  4. b()c() 不是“没耗时”,而是“作为通道”:它们的宽度反映了它们调用的子函数的耗时。它们本身可能不耗时,但它们是耗时路径的一部分。
  5. a() 的分支差异明显b() 分支远比 h() 分支耗时,这提示 a() 内部的条件逻辑可能导致了性能差异。

c、最终建议

  • 优先调查 g():这是最明显的热点。
  • 其次调查 b() 分支的完整调用链:从 b()c()d()f()g()
  • 分析 a() 的代码:确认 b()h() 分支的条件逻辑,看看是否可以优化 b() 分支的执行效率或减少其执行频率。
  • 忽略 i()h():除非你发现其他问题,否则它们不是当前的优化重点。

4、如何解读?

  • 找最宽的块:位于顶部(叶子节点)的宽块通常是直接消耗资源的函数,是优化的首要目标。
  • 看调用链:从一个宽块向下追踪,可以清晰地看到是哪个调用路径导致了该函数的频繁执行。
  • 识别“平顶” vs “尖顶”:
    • 平顶(如 malloc):表示该函数自身消耗资源,是性能瓶颈。
    • 尖顶(如 main):表示该函数主要消耗在调用子函数上,瓶颈在其子函数中。

5、如何生成火焰图?

1)数据采集

  • 使用性能分析工具采集调用栈数据。
  • 常用工具:
    • Linux: perf (perf record)
    • Java: async-profiler, jstack, JFR
    • 通用: eBPF/bpftrace

1、启动 profiler

$ profiler start
Started [cpu] profilin

2、获取已采集的 sample 的数量

$ profiler getSamples
23

3、查看 profiling 状态:可以查看当前 profiler 在采样哪种event和采样时间。

$ profiler status
[cpu] profiling is running for 4 seconds

4、停止 profiler:生成火焰图格式结果

默认情况下,结果是 Flame Graph 格式的 html 文件,也可以用 -o--format 参数指定其他内容格式,包括 flat、traces、collapsed、flamegraph、tree、jfr。

$ profiler stop --format flamegraph
profiler output file: /tmp/test/arthas-output/20211207-111550.html
OK

--file参数指定的文件名后缀为 htmljfr 时,文件格式可以被推断出来。比如--file /tmp/result.html 将自动生成火焰图。

5、通过浏览器查看 arthas-output 下面的 profiler 结果

默认情况下,arthas 使用 3658 端口,则可以打开: http://localhost:3658/arthas-output/ 查看到arthas-output目录下面的 profiler 结果:

image-20251016111026613

2)数据处理

  • 将原始的调用栈数据(通常是堆栈跟踪列表)转换成火焰图工具能识别的格式(通常是折叠栈格式:func1;func2;func3 10,表示调用栈func1->func2->func3 出现了10 次)。
  • 这一步可能需要编写脚本或使用工具(如stackcollapse-perf.pl for perf data)。

3)生成可视化

  • 使用 FlameGraph 开源工具(由 Brendan Gregg 开发)的 flamegraph.pl 脚本,将折叠栈数据转换为 SVG 格式的火焰图。
  • 命令示例:flamegraph.pl collapsed_stacks.txt > output.svg
  • 生成的 SVG 文件可在浏览器中打开,支持鼠标悬停查看详情、点击缩放等交互操作

6、优缺点

1)优点

  • 直观清晰:一目了然地看到性能瓶颈。
  • 信息丰富:同时展示调用关系和资源消耗。
  • 交互性强:可缩放、搜索、高亮。
  • 跨平台:原理通用,可用于多种语言和系统。

2)缺点

  • 基于采样:是统计结果,可能存在误差,不一定捕获到瞬时峰值。
  • 无法显示代码逻辑:只显示“谁在运行”,不显示“为什么这样运行”。
  • 需要符号信息:要获得有意义的函数名,程序需要编译时包含调试符号(如-g)。
  • 对短生命周期程序不敏感:如果程序运行时间很短,可能采样不到足够的数据。

三、Java Flight Recorder

Java Flight RecorderJava 开发者和运维人员不可或缺的工具。它就像一个“黑匣子”,能够记录应用在运行时的详尽信息。结合 Java Mission Control,可以快速定位性能瓶颈、分析 GC 问题、排查疑难杂症,极大地提升了 Java 应用的可观测性和可维护性。对于任何严肃的 Java 生产环境,掌握 JFR 的使用都是必备技能。

1、核心概念

1)概念

JDK 飞行记录器 ( JFR )是一种结构化日志记录工具, 它记录广泛的系统级( system-level )事件。JFR 会持续记录 JVM 中的 一系列事件,用于诊断问题。这种方式的优势是,它会按时间顺序,捕获导致事故的,详细系统信息。JFR 被设计的,对于性能影响很小,所以 可以安全地在生产环境长时间运行。对于运行系统的影响比较小,额外占用资源小于 1%,但是随着开始的事件或者记录线程增多,性能开销也会随之增多

  • 事件 (Events): JFR 的核心是事件。它会记录各种类型的事件,例如:
    • JVM 内部事件: GC 活动、JIT 编译、线程活动、类加载/卸载。
    • 应用程序事件: 方法执行(通过探针或注解)、锁竞争、I/O 操作、异常抛出。
    • 系统事件: CPU 使用率、内存使用情况、网络活动。
    • 自定义事件: 开发者可以定义自己的事件来记录特定的业务逻辑。
  • 记录 (Recording): JFR 收集的数据被组织成一个“记录”文件(通常是 .jfr 文件)。这个文件包含了在特定时间段内发生的事件的二进制数据。
  • 开销极低: JFR 的设计目标之一是生产环境可用,其默认配置下的性能开销通常低于 2%,使其非常适合在生产系统中进行问题诊断。

3)主要功能

  • 性能分析 (Profiling):
    • CPU 分析: 精确地找出消耗 CPU 时间最多的方法(采样或基于事件)。
    • 内存分析: 分析对象分配热点,了解哪些代码创建了大量对象。
    • 锁分析: 识别线程阻塞和锁竞争,帮助解决并发性能问题。
  • 垃圾回收 (GC) 分析:详细记录每次 GC 的类型、持续时间、回收的内存量、堆内存变化等,是调优 GC 性能的关键工具。
  • 应用监控与故障排查:
    • 当应用出现卡顿、高延迟或崩溃时,可以通过分析 JFR 记录回溯问题发生时的系统状态。
    • 记录异常堆栈信息。
  • 容量规划与基准测试:通过长期记录,了解应用在不同负载下的资源消耗模式,为容量规划提供数据支持。

2、如何使用 JFR

1)JDK 版本

如果你使用的 JDK 版本为 JDK11 及以上的版本,那么恭喜你~你将可以免费使用 Java Flight Recorder

  • Oracle JDK8 及以上版本‌:需通过添加 -XX:+UnlockCommercialFeatures参数启用(仅限商业用途)。 ‌

  • •‌OpenJDK 11 及以上版本‌:免费开源版本,无需商业授权即可使用。 ‌

特性 JDK 8 (Oracle JDK) JDK 11+ (OpenJDK / Oracle JDK)
UnlockCommercialFeatures 必须添加,放最前面 已废弃,添加会报错
FlightRecorder 需要手动开启 默认开启,可省略
JFR 是否免费 商业特性(需授权) 完全开源免费
dumponexit=true 支持 支持
settings=profile 支持 支持

2)JVM 参数

-XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:StartFlightRecording=filename=/export/Logs/recording.jfr,dumponexit=true,settings=profile,delay=10s
参数 说明 备注
-XX:+UnlockCommercialFeatures 解锁 JDK 中的商业特性 这个参数在 OpenJDK 8不存在
-XX:+FlightRecorder 启用 Flight Recorder 功能 JDK 8 中需要显式开启。从 JDK 11+ 开始,JFR 默认是启用的
-XX:StartFlightRecording=... JVM 启动时立即开始一个 Flight Recording 以下是对应的参数解释

-XX:StartFlightRecording=...

  • duration: 记录时长(例如 60s, 5m)。
  • filename: 输出文件名。
  • settings: 使用预设的配置文件(如 profile, default)。
  • maxAge, maxSize: 循环记录时的限制。
  • delay:系统启动 + 预热需要 10 分钟左右的时间,所以延迟监控
    • 如果你的应用启动很快,且主要关注稳定运行时的性能(如在线服务的日常监控),那么 delay=10m 是一个合理的选择,可以过滤掉预热期的噪音。
    • 如果你的应用启动较慢,或者你正在排查启动慢、初始化异常等问题,那么 delay=10m 是不合适的,应该移除或缩短延迟时间(如 delay=30s
Settings 名称 用途 性能开销 适用场景
default 标准事件(CPU、内存、GC、线程等) 低 (~1%) 通用分析
profile 更详细的事件(方法采样、分配率等) 中 (~2-5%) 深度性能分析
lowoverhead 仅关键事件(GC、异常等) 极低 (<1%) 生产环境长期监控
continuous 环形缓冲区模式(不写入磁盘) 生产环境诊断

3)问题

a、为啥开销比较低

JFR 的低开销不是偶然的,而是通过架构设计、底层实现和精细化控制共同实现的。正因如此,它成为目前最适合在生产环境中长期开启的 Java 性能诊断工具

特性 如何降低开销 说明
事件驱动 只记录关键事件,不侵入业务逻辑 JFR 不是持续记录所有方法调用或对象分配,而是只记录特定的、预定义的“事件”
JVM 内建 使用 C++ 实现,避免 Java 层开销 JFR 是 JVM 内部原生实现的,而不是一个外部代理或 Java 库。
线程本地缓冲 减少锁竞争,异步提交 JFR 为每个线程分配一个本地缓冲区(Thread-Local Buffer),事件先写入本地缓冲,而不是直接写入全局文件或共享结构。
可配置采样 按需开启,灵活控制粒度 JFR 允许你精细控制哪些事件开启、采样频率多高,从而平衡开销与信息量。
高效二进制格式 节省存储和 I/O JFR 记录的数据是高度优化的二进制格式
生产级优化 经过多年大规模验证  

三、Java Mission Control (JMC)

如果 Java Flight Recorder 是 “黑匣子” 那么 Java Mission Control 就是打开 “黑匣子” 的的钥匙。

1、介绍

1)是什么?

Java Flight Recorder (JFR)JVM 内置的低开销运行时数据记录引擎,负责采集性能数据并生成 .jfr 二进制文件;而 Java Mission Control (JMC) 是其官方配套的高级分析与可视化工具,能将这些难以直接解读的数据转化为直观的图形、表格和图表,帮助开发者进行性能分析、故障排查和 JVM 调优,现已发展为功能全面的 Java 应用性能管理“一站式平台”。

  • 现代替代方案

    • 虽然 JMC 是官方工具,但社区也有其他工具支持 .jfr

      文件,如:

      • jfr 命令行工具(JDK 自带)
      • Async-Profiler + Flame Graph
  • JMC 的独立性

    • JMC 可以独立安装,也可以集成在 IDE 中(如 IntelliJ IDEA 插件)。

    • 它既能分析离线的 .jfr 文件,也能连接运行中的 JVM 进行实时监控。

2)应用场景

  • 性能调优:当你的 Java 应用出现性能瓶颈时,JMC 可以帮助你识别哪些代码段消耗了大量资源,从而指导优化工作。

  • 故障排查:如果应用出现异常或者挂起,可以通过 JMC 查看当时的线程堆栈、内存状态等信息,快速定位问题。

  • 监控生产环境:在生产环境中,JMC 的飞行记录器可以持续收集数据,为运维团队提供宝贵的诊断信息。

3)特点与优势

  • 轻量级:JMC 对应用性能的影响极小,即使是高负载环境也能胜任。

  • 全面的数据采集:覆盖了从 JVM 内部到应用层的各种运行指标,提供全方位的洞察。

  • 易用性:直观的 GUI 设计,使得即使是不熟悉命令行的开发者也能轻松上手。

4、安装

https://www.oracle.com/java/technologies/javase/jmc9-release-notes.html

启动测试代码后,启动 JMC 就可以在左侧的 JMV 浏览器中看到当前机器所有的JVM 进程,选择测试代码进行通过 MBean 服务器进行连接,然后可以看到概览界面。

image-20251017182507147

2、整体布局

JMC 界面分为左右两大部分:

位置 说明 功能
左侧 JVM 浏览器(JVM Browser 列出当前系统中所有可连接的 Java 进程(JVM)
右侧 监控面板与分析视图 显示选中 JVM 的实时性能数据、内存、线程等信息

1)左侧:JVM 浏览器

  • 功能:显示本机或远程运行的所有 Java 虚拟机(JVM),您可以从中选择一个进行监控或分析。

  • 问题 1: 为什么你没启动 Java 应用,却能看到 JVM

    • 打开了 IDEA,它本身就是一个 Java 应用。
    • 它会启动多个 JVM 实例:
      • 主程序:com.intellij.idea.Main
      • Maven/Gradle 构建服务器:RemoteMavenServer36
      • 插件、代码分析、索引等子进程

2)右侧:概览面板

a、仪表盘

位置 指标 含义
仪表盘 Used Java Heap Memory 当前 JVM 堆内存使用量(MB
  JVM CPU Usage JVM 所占 CPU 使用率
  Live Set + Fragmentation 堆中“存活对象”占用空间比例 + 内存碎片化程度

b、处理器使用率图表

  • 显示 JVM CPU 使用率机器整体 CPU 使用率
  • 可见 JVM 占用非常低( < 5% ),说明当前应用负载很轻

image-20251017183117510

c、内存使用图表(Memory)

  • 显示不同内存区域的变化趋势
  • 关键项:
    • Committed Java Heap:已提交给 JVM 的堆内存
    • Total Physical Memory:物理内存总量
    • Used Java Heap Memory:堆内存实际使用量
    • Used Physical Memory:系统总内存使用量

image-20251017183232883

d、下方标签页:深入分析功能

标签 功能
概览 当前页面,显示基础监控数据
MBean 浏览器 查看 JVM 中暴露的 MBeans(管理接口),可用于自定义监控
触发器 设置事件触发条件(如内存超过阈值时报警)
系统 查看操作系统信息、文件系统、网络等
内存 深入分析堆内存,支持堆转储(Heap Dump)分析
线程 查看线程状态、死锁、阻塞情况
诊断命令 执行 JMX 命令,如强制 GC、dump 堆栈等

3、实时分析

1)JMC 触发器

JMC 触发器可以理解为一个 JVM 告警,可以对 JVM 进程的各种指标设置阈值,在超过指定阈值后可以收到告警提示,对进程异常情况监控十分方便。


/**
 * 消耗CPU的线程 通过不断地进行浮点运算来提高对 CPU 的消耗。
 */
private static void cpuHigh() {
    Thread thread = new Thread(() -> {
        Thread.currentThread().setName("cpu_high_thread");
        while (true){
            double pi = 0;
            for (int i = 0; i < Integer.MAX_VALUE; i++) {
                pi += Math.pow(-1, i) / (2 * i + 1);
            }
            System.out.println("Pi: " + pi * 4);
        }
    });
    thread.start();
}

通过弹窗告警可以看到告警原因,以及对应的类信息,但是这里目前还看不到告警的具体原因,也就是说比如 CPU 占用率过高,并不知道为什么 CPU 会使用过高。

image-20251020104122070

2)JMC 分析内存

/**
 * 不断新增 BigDecimal 信息到 list,每秒10000个
 */
private static void allocate() {
    new Thread(()->{
        Thread.currentThread().setName("memory_allocate_thread");
        List<BigDecimal> list = new ArrayList<>();
        for (int i = 0; i < Integer.MAX_VALUE; i++) {
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            for (int i1 = 0; i1 < 10; i1++) {
                list.add(new BigDecimal(i));
            }
        }
    }).start();
}

通过内存页面可以看到堆内存分配情况,由于问题代码中再不断地分配 BigDecimal 对象,这里也可以看出 BigDecimal 对象占用了最多的内存。对分析内存过高情况有一定的帮助。

image-20251020130414796

3)内存分配对应的线程

如果想进一步分析内存占用来源,可以到线程页面,通过勾选分配复选框,可以看到哪个线程占用的内存最多,还可以看到线程的具体的调用堆栈。

image-20251020130541325

4)JMC 分析 CPU

线程页面勾选 CPU 概要分析可以查看占用 CPU 最高的线程,这里线程 cpu_high_thread 在不断地进行浮点计算,占用了较多的 CPU

image-20251020130806121

5)JMC 分析死锁

线程页面勾选死锁检测可以直接看到死锁线程信息,并且有具体的线程堆栈。

image-20251020105706854

另外一种检查死锁的方式是直接打印线程信息,在线程信息的最后部分,会输出死锁线程信息。使用 JMC 可以通过诊断命令中的 Thread.print 命令来实现这个功能。

image-20251020105729183

4、离线分析

1)获取 JRC 文件

image-20251020131014069

2)自动分析image-20251020131949301

3)异常错误分析

双击自动分析结果中规则名称为:引发的异常错误 或 点击左边菜单栏Java应用程序-》异常错误,利用界面底部的火焰图信息,我们能够定位并分析相关异常错误的调用栈

四、Arthas

1、什么是 Arthas

Arthas 是阿里开源的一款 Java 诊断工具,可以在不修改代码、不重启服务的情况下,对线上运行的 Java 应用进行实时诊断,例如:

  • 查看方法调用栈、参数、返回值
  • 动态追踪方法执行耗时(trace)
  • 监控 JVM 状态(线程、内存、GC 等)
  • 热更新代码(通过 redefine/retransform)
  • 反编译已加载的 class
  • 条件断点、监控特定方法调用等

通常使用方式是 attach 到目标 Java 进程,但需要手动操作或脚本支持。

2、SpringBoot 接入

1)arthas-spring-boot-starter

arthas:
  enabled: true
  tunnel-server: ws://127.0.0.1:7777/ws
  agent-id: my-app-01
  telnet-port: 3658
  http-port: 8563
<dependency>
    <groupId>com.taobao.arthas</groupId>
    <artifactId>arthas-spring-boot-starter</artifactId>
    <version>最新版本 4.0.3</version>
</dependency>

2)arthas-spring-boot-starter 的作用

这个 starter 的核心价值是:让 Arthas 在 Spring Boot 应用启动时自动嵌入并开启服务,无需手动 attach。

  1. 自动集成 Arthas Agent
    • 应用启动时自动加载 Arthas,并以内嵌模式(telnet 或 web console)运行。
  2. 提供 Web 控制台(可选)
    • 默认开启 Web UI(如 http://localhost:8563),可通过浏览器直接使用 Arthas。

3)使用场景

Arthas 本身不“吃”CPU,但用错了命令会“吃掉”你的应用 CPU

  • 开发/测试环境:快速调试接口、查看方法执行逻辑。
  • 生产环境(谨慎使用):紧急排查性能问题、死锁、异常调用链等。
  • 容器化部署(如 Kubernetes):通过 Web Console Tunnel 远程接入诊断。
使用方式 CPU 开销 是否适合生产
attach,不执行命令 极低(≈0) 安全
执行 dashboard / jvm 很低 安全
执行 thread -n 3(默认间隔) 低~中(因 JDK 而异) 谨慎使用
长时间 trace / watch 高频方法 (可能雪崩) 禁止
profiler start(火焰图) 低(<2%) 推荐

4)注意事项

  • 安全风险Arthas 拥有极高权限(可执行任意代码),切勿在公网暴露端口
  • 建议配合防火墙、认证或仅限内网访问。
  • 生产环境建议通过 arthas.tunnel-server + 白名单方式远程接入,而非直接开放 HTTP/Telnet 端口。

五、FAQ

1、ArthasJava Flight Recorder

维度 Arthas Java Flight Recorder (JFR)
开发方 阿里巴巴(开源) Oracle
是否需要重启/attach attach 到运行中进程,或通过 starter 嵌入 默认内置,无需额外工具,可启动时开启或动态启用
交互方式 交互式命令行/Web 控制台,实时执行命令(如 tracewatchmonitor 录制 + 离线分析,生成 .jfr 文件后用工具
实时性 强:可实时查看方法调用、参数、返回值、修改行为等 弱:需先录制一段时间,再分析历史数据
代码级调试能力 极强:支持反编译、动态 trace、条件监控、热更新字节码等 无:不能查看方法参数/返回值,不能干预程序执行
性能开销 中等(按需启用,命令触发时才有开销) 极低(设计目标就是低开销持续录制)
主要用途 线上问题快速排查、动态诊断、调试 性能剖析、长时间运行分析、JVM/系统级事件追踪
是否能修改程序行为 可以(如 redefine class) 不能
是否开源免费 是(Apache 2.0) OpenJDK 11+ 免费;Oracle JDK 8 需商业许可

1)你想看某个方法的入参和返回值?

  • Arthas:用 watch com.example.Service method "{params, returnObj}" 实时打印。
  • JFR:做不到。JFR 不记录具体业务方法的参数/返回值(除非你手动埋点 Event)。

2)你想分析 CPU 热点或 GC 行为?

  • JFR:原生支持,低开销录制 CPU、内存、线程、GC、I/O 等事件,可视化分析强大。
  • Arthas:可通过 threaddashboard 看基础指标,但深度不如 JFR。

3)你想在线上不停机的情况下调试?

  • Arthas:专为此设计,支持动态追踪、反编译、甚至临时修复(redefine)。
  • JFR:只能“记录”,不能“干预”或“交互”。

4)你想做长期性能基线监控?

  • JFR:适合持续录制(如每小时一段),用于趋势分析。
  • Arthas:不适合长期自动采集,更适合“按需诊断”。

5)使用场景

场景 推荐工具
线上突发问题排查(如接口慢、异常) Arthas
性能优化、CPU/内存瓶颈分析 JFR + JDK Mission Control
需要看方法内部参数/返回值 Arthas
低开销、7x24 小时监控 JVM 行为 JFR
不能重启服务,但要调试代码逻辑 Arthas

ContactAuthor