Skip to content

第三方诊断工具与实战

除了JDK自带的工具外,还有许多优秀的第三方诊断工具可以帮助我们更高效地排查和解决Java应用问题。本文将介绍Arthas、JProfiler等工具的使用方法,以及完整的故障排查实战流程。

Arthas: 阿里巴巴开源诊断利器

Arthas是阿里巴巴开源的功能强大的在线诊断工具,无需修改代码即可排查问题。

Arthas核心功能

mermaid
graph TB
    A["Arthas核心功能"] --> B["dashboard<br/>实时面板"]
    A --> C["thread<br/>线程分析"]
    A --> D["jad<br/>反编译"]
    A --> E["watch<br/>方法监控"]
    A --> F["trace<br/>调用链路"]
    A --> G["monitor<br/>方法统计"]
    A --> H["tt<br/>时光隧道"]
    
    E --> E1["观察方法入参<br/>返回值<br/>异常信息"]
    F --> F1["统计方法耗时<br/>调用路径"]
    H --> H1["记录方法调用<br/>支持重放"]
    
    style A fill:#5C6BC0,stroke:#3949AB,stroke-width:3px,color:#fff
    style E fill:#81C784,stroke:#388E3C,stroke-width:2px,color:#1B5E20
    style F fill:#64B5F6,stroke:#1976D2,stroke-width:2px,color:#0D47A1
    style H fill:#CE93D8,stroke:#7B1FA2,stroke-width:2px,color:#4A148C

快速启动

bash
# 下载arthas启动脚本
$ curl -O https://arthas.aliyun.com/arthas-boot.jar

# 启动并选择进程
$ java -jar arthas-boot.jar
[INFO] arthas-boot version: 3.7.1
[INFO] Found existing java process, please choose one and input the serial number.
* [1]: 8234 com.example.order.OrderServiceApplication
  [2]: 9156 com.example.product.ProductServiceApplication
1

# 连接成功后进入交互界面
[arthas@8234]$

常用命令详解

dashboard - 实时监控面板

bash
[arthas@8234]$ dashboard

ID   NAME                          GROUP          PRIORITY  STATE     %CPU      DELTA_TIME TIME      INTERRUPT DAEMON
1    main                          main           5         WAITING   0.0       0.000      0:0.031   false     false
2    Reference Handler             system         10        WAITING   0.0       0.000      0:0.000   false     true
3    Finalizer                     system         8         WAITING   0.0       0.000      0:0.000   false     true

Memory                    used      total     max      usage     GC
heap                      128M      256M      1024M    12.50%    
eden_space                64M       128M      256M     25.00%    gc.ps_scavenge.count          45
survivor_space            8M        16M       32M      25.00%    gc.ps_scavenge.time(ms)       342
old_gen                   56M       112M      736M     7.61%     gc.ps_marksweep.count         2
nonheap                   48M       50M       -1       96.00%    gc.ps_marksweep.time(ms)      158

thread - 线程分析

bash
# 查看最繁忙的5个线程
[arthas@8234]$ thread -n 5
"http-nio-8080-exec-1" Id=15 RUNNABLE (in native)
    at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)
    at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:269)
    ...

# 查看指定线程的堆栈
[arthas@8234]$ thread 15
"http-nio-8080-exec-1" Id=15 RUNNABLE
    at com.example.order.OrderService.processOrder(OrderService.java:45)
    ...

# 查看阻塞其他线程的线程
[arthas@8234]$ thread -b
No most blocking thread found!

# 查看死锁
[arthas@8234]$ thread --state BLOCKED

jad - 反编译

bash
# 反编译类
[arthas@8234]$ jad com.example.order.OrderService

ClassLoader:
+-sun.misc.Launcher$AppClassLoader@18b4aac2
  +-sun.misc.Launcher$ExtClassLoader@1dde4cb2

Location:
/app/order-service.jar

/*
 * Decompiled with Arthas
 */
package com.example.order;

public class OrderService {
    public Order processOrder(OrderRequest request) {
        // 反编译后的代码...
    }
}

watch - 方法监控

bash
# 观察方法的入参和返回值
[arthas@8234]$ watch com.example.order.OrderService createOrder "{params, returnObj}" -x 3
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 28 ms
ts=2024-11-27 10:15:23; result=@ArrayList[
    @Object[][
        @OrderRequest[id=12345, amount=199.00],
    ],
    @Order[id=67890, status=CREATED],
]

# 只观察抛出异常的调用
[arthas@8234]$ watch com.example.order.OrderService createOrder "{params, throwExp}" -e

# 观察方法执行前后对象变化
[arthas@8234]$ watch com.example.order.OrderService createOrder "{params[0], target.cache.size()}" -b -s

trace - 调用链路追踪

bash
# 追踪方法调用路径和耗时
[arthas@8234]$ trace com.example.order.OrderService createOrder
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 45 ms
`---ts=2024-11-27 10:20:15;thread_name=http-nio-8080-exec-1;id=15;is_daemon=true;priority=5;
    `---[156.789ms] com.example.order.OrderService:createOrder()
        +---[0.123ms] com.example.order.OrderValidator:validate()
        +---[45.678ms] com.example.order.OrderRepository:save() #slow
        +---[100.234ms] com.example.payment.PaymentClient:charge() #slow
        `---[10.456ms] com.example.notification.NotificationService:notify()

# 只显示耗时超过100ms的调用
[arthas@8234]$ trace com.example.order.OrderService createOrder '#cost > 100'

monitor - 方法统计

bash
# 统计方法调用次数和耗时(每5秒统计一次)
[arthas@8234]$ monitor -c 5 com.example.order.OrderService createOrder
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 28 ms
 timestamp            class                                  method       total  success  fail  avg-rt(ms)  fail-rate
-----------------------------------------------------------------------------------------------------------------------------
 2024-11-27 10:25:00  com.example.order.OrderService         createOrder  150    148      2     45.23       1.33%
 2024-11-27 10:25:05  com.example.order.OrderService         createOrder  163    160      3     52.18       1.84%

tt - 时光隧道

bash
# 记录方法调用
[arthas@8234]$ tt -t com.example.order.OrderService createOrder
Press Q or Ctrl+C to abort.
 INDEX   TIMESTAMP            COST(ms)  IS-RET  IS-EXP   OBJECT         CLASS                          METHOD
-----------------------------------------------------------------------------------------------------------------------------
 1000    2024-11-27 10:30:01  45.123    true    false    0x1a2b3c4d     OrderService                   createOrder
 1001    2024-11-27 10:30:02  52.456    true    false    0x1a2b3c4d     OrderService                   createOrder
 1002    2024-11-27 10:30:03  0.000     false   true     0x1a2b3c4d     OrderService                   createOrder

# 查看某次调用的详细信息
[arthas@8234]$ tt -i 1002
 INDEX          1002
 GMT-CREATE     2024-11-27 10:30:03
 COST(ms)       0.000
 IS-RETURN      false
 IS-EXCEPTION   true
 THROW-EXCEPTION   java.lang.NullPointerException
 OBJECT         0x1a2b3c4d
 CLASS          com.example.order.OrderService
 METHOD         createOrder

# 重放某次调用
[arthas@8234]$ tt -i 1000 -p

Arthas命令速查表

命令功能常用参数
dashboard实时面板-i 刷新间隔
thread线程分析-n 显示前n个, -b 阻塞分析
jad反编译--source-only 只显示源码
watch方法监控-x 展开层级, -e 只看异常
trace调用追踪--skipJDKMethod 跳过JDK方法
monitor方法统计-c 统计周期
tt时光隧道-t 记录, -i 查看, -p 重放
sc搜索类-d 显示详情
sm搜索方法-d 显示详情
heapdump生成dump--live 只导出存活对象
profiler火焰图start/stop/getSamples

JProfiler: 商业级性能分析工具

JProfiler是功能强大的商业JVM分析工具,提供直观的可视化界面和丰富的分析功能。

核心特性

mermaid
graph LR
    A["JProfiler功能"] --> B["实时内存分析"]
    A --> C["CPU性能剖析"]
    A --> D["线程分析"]
    A --> E["数据库分析"]
    
    B --> B1["内存泄漏检测<br/>对象分配热点<br/>GC分析"]
    C --> C1["热点方法<br/>调用树<br/>火焰图"]
    D --> D1["线程历史<br/>锁竞争<br/>死锁检测"]
    E --> E1["SQL执行统计<br/>慢查询分析"]
    
    style A fill:#5C6BC0,stroke:#3949AB,stroke-width:3px,color:#fff
    style B fill:#81C784,stroke:#388E3C,stroke-width:2px,color:#1B5E20
    style C fill:#EF5350,stroke:#C62828,stroke-width:2px,color:#fff

JProfiler主要功能

1. CPU分析

  • 采样分析: 低开销定位热点方法
  • 调用树: 展示方法调用关系
  • 热点方法: 按CPU时间排序的方法列表
  • 火焰图: 直观展示CPU时间分布

2. 内存分析

  • 对象分配热点: 哪些代码创建了最多对象
  • 内存增长趋势: 实时监控各类对象增长
  • 泄漏检测: 自动识别潜在内存泄漏

3. 线程分析

  • 线程状态历史: 可视化线程状态变化
  • 锁竞争分析: 找出锁等待热点
  • 死锁检测: 自动检测死锁

4. 数据库分析

  • JDBC调用统计
  • 慢SQL分析
  • 连接池监控

故障排查实战流程

典型故障排查流程

mermaid
flowchart TD
    A["应用响应缓慢"] --> B["jstat查看GC频率"]
    B --> C{"GC频繁?"}
    
    C -->|是| D["分析GC日志<br/>调整堆内存参数"]
    C -->|否| E["jstack查看线程状态"]
    
    E --> F{"发现BLOCKED?"}
    F -->|是| G["检查锁竞争<br/>优化同步代码"]
    F -->|否| H["Arthas trace<br/>定位慢方法"]
    
    H --> I["优化业务逻辑<br/>数据库查询"]
    
    style A fill:#EF5350,stroke:#C62828,stroke-width:3px,color:#fff
    style D fill:#81C784,stroke:#388E3C,stroke-width:2px,color:#1B5E20
    style G fill:#FFB74D,stroke:#F57C00,stroke-width:2px,color:#E65100
    style I fill:#64B5F6,stroke:#1976D2,stroke-width:2px,color:#0D47A1

内存持续增长排查流程

mermaid
sequenceDiagram
    participant Admin as 运维人员
    participant Monitor as 监控系统
    participant JMap as jmap工具
    participant MAT as MAT工具
    participant Dev as 开发人员
    
    Monitor->>Admin: 内存告警
    Admin->>JMap: 生成堆转储
    JMap->>MAT: 加载dump文件
    MAT->>MAT: 分析Leak Suspects
    MAT->>MAT: 查看Dominator Tree
    MAT->>Admin: 定位泄漏对象
    Admin->>Dev: 提供分析报告
    Dev->>Dev: 修复内存泄漏

实战案例: 订单服务响应缓慢

案例背景

某电商订单服务在促销期间出现响应缓慢,偶尔超时。

诊断步骤

mermaid
flowchart TD
    A["问题: 订单服务慢"] --> B["Step1: jstat监控GC"]
    B --> C["发现: Young GC频繁<br/>每2秒一次"]
    
    C --> D["Step2: jmap -heap查看堆"]
    D --> E["发现: 新生代仅500MB<br/>Eden区快速填满"]
    
    E --> F["Step3: 调整参数<br/>-Xmn2g扩大新生代"]
    F --> G["Step4: 重启验证"]
    
    G --> H["结果: GC间隔延长至30秒<br/>响应时间降低60%"]
    
    style A fill:#EF5350,stroke:#C62828,stroke-width:3px,color:#fff
    style C fill:#FFB74D,stroke:#F57C00,stroke-width:2px,color:#E65100
    style E fill:#FFCC80,stroke:#E65100,stroke-width:2px,color:#BF360C
    style H fill:#81C784,stroke:#388E3C,stroke-width:2px,color:#1B5E20

诊断命令记录

bash
# 1. 查找目标进程
$ jps -l
12345 com.ecommerce.OrderService

# 2. 监控GC情况(每秒输出一次)
$ jstat -gcutil 12345 1000
  S0     S1     E      O      M     YGC    FGC    GCT
 12.50   0.00  98.76  45.23  89.34  1523     3    12.456
  0.00  15.32  23.45  45.67  89.45  1524     3    12.467
  
# 3. 查看堆配置
$ jmap -heap 12345 | grep -A 5 "NewSize"
NewSize = 524288000 (500.0MB)
MaxNewSize = 524288000 (500.0MB)

# 4. 查看当前JVM参数
$ jinfo -flags 12345 | grep Xmn
-Xmn500m

# 5. 修改启动参数后重启,再次验证
$ jstat -gcutil 12345 1000
  S0     S1     E      O      M     YGC    FGC    GCT
  8.23   0.00  34.56  28.45  87.23   45     1     2.345

工具选型与组合策略

不同场景的工具选择

mermaid
graph TB
    A["问题类型"] --> B["性能缓慢"]
    A --> C["内存泄漏"]
    A --> D["CPU飙高"]
    A --> E["线程死锁"]
    A --> F["频繁GC"]
    
    B --> B1["1. jstack查线程<br/>2. Arthas trace<br/>3. JProfiler剖析"]
    C --> C1["1. jmap生成dump<br/>2. MAT分析<br/>3. VisualVM监控"]
    D --> D1["1. top -Hp定位线程<br/>2. jstack分析<br/>3. Arthas profiler"]
    E --> E1["1. jstack检测<br/>2. JConsole可视化<br/>3. Arthas thread"]
    F --> F1["1. jstat监控GC<br/>2. GC日志分析<br/>3. VisualGC可视化"]
    
    style A fill:#5C6BC0,stroke:#3949AB,stroke-width:3px,color:#fff

诊断工具最佳实践

命令行工具使用技巧

  1. 组合使用命令: 先用jps定位进程,再用jstat监控,最后用jmap/jstack诊断
  2. 避免频繁dump: 生成堆转储会暂停应用,生产环境需谨慎操作
  3. 保留历史快照: 定期保存线程快照和GC日志,便于问题回溯
  4. 自动化脚本: 编写监控脚本定时采集jstat数据,绘制趋势图

可视化工具使用建议

mermaid
graph TB
    A["可视化工具选型"] --> B["开发测试环境"]
    A --> C["生产环境"]
    
    B --> B1["首选VisualVM<br/>功能全面免费"]
    B --> B2["深度分析用JProfiler<br/>商业工具更专业"]
    
    C --> C1["远程监控用JConsole<br/>轻量级稳定"]
    C --> C2["紧急排查用Arthas<br/>无侵入在线诊断"]
    C --> C3["离线分析用MAT<br/>生成dump后分析"]
    
    style A fill:#5C6BC0,stroke:#3949AB,stroke-width:3px,color:#fff
    style B1 fill:#81C784,stroke:#388E3C,stroke-width:2px,color:#1B5E20
    style C2 fill:#CE93D8,stroke:#7B1FA2,stroke-width:2px,color:#4A148C

性能分析黄金法则

  1. 先整体后局部: 先看整体资源使用(CPU、内存、GC),再深入方法级分析
  2. 先现象后原因: 先观察现象(慢、OOM、死锁),再分析根本原因
  3. 先工具后代码: 先用工具定位问题范围,再review代码细节
  4. 对比基线数据: 记录正常状态下的性能基线,异常时对比分析
  5. 生产环境谨慎: 避免使用会暂停应用的操作,优先使用无侵入工具

工具资源与学习路径

官方文档

工具官方文档
JDK工具Oracle JDK Tools Reference
VisualVMhttps://visualvm.github.io/
MATEclipse MAT Help
Arthashttps://arthas.aliyun.com/doc/

在线分析工具

工具地址用途
GCEasyhttps://gceasy.io/GC日志在线分析
FastThreadhttps://fastthread.io/线程dump在线分析
HeapHerohttps://heaphero.io/堆dump在线分析

推荐学习资源

  1. 《Java性能权威指南》: 深入讲解JVM性能调优方法论
  2. 《深入理解Java虚拟机》: JVM原理与工具使用的经典教材
  3. Arthas官方教程: 系统学习Arthas的使用方法

总结

JVM诊断工具是Java应用性能调优和故障排查的利器。在实际工作中,应根据问题类型选择合适的工具组合:

问题类型推荐工具组合
性能问题jstat + Arthas trace + JProfiler
内存泄漏jmap + MAT
线程问题jstack + JConsole
GC调优GC日志 + VisualGC

掌握这些工具的使用,结合对JVM原理的深入理解,就能快速定位并解决各类生产环境问题,保障Java应用的稳定高效运行。记住,工具只是手段,理解问题本质才是关键。

更新: 2025-12-06 15:42:37
原文: https://www.yuque.com/u22210564/zoxfmt/farbgwe2u4xc088z

Java 后端面试知识库