这是《JVM 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 Arthas 是阿里开源的 Java 在线诊断工具。它允许 attach 到运行中的 JVM,查看线程、内存、类加载、方法调用、参数返回值和耗时,适合在测试或受控生产环境中定位疑难问题。
使用在线诊断工具要遵守权限和变更流程:它可能读取敏感数据,增强类也会带来少量开销。
24.1 安装与启动
下载并启动:
curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar
启动后会列出 Java 进程,输入编号 attach。
也可以直接指定 pid:
java -jar arthas-boot.jar <pid>
退出并释放增强:
stop
如果只执行 exit,本地会话退出,但服务端可能仍在。生产用完应执行 stop。
24.2 基础命令
| 命令 | 用途 |
|---|---|
dashboard |
总览 |
thread |
线程列表和栈 |
jvm |
JVM 信息 |
sysprop |
系统属性 |
sysenv |
环境变量 |
sc |
查看已加载类 |
sm |
查看方法 |
jad |
反编译类 |
getstatic |
读取静态字段 |
heapdump |
导出堆 |
logger |
查看和修改日志级别 |
示例:
dashboard
thread -n 5
thread -b
jvm
sc -d com.demo.OrderService
thread -b 用于找出阻塞其他线程最多的锁持有线程。
24.3 watch 方法
watch 可以观察方法入参、返回值和异常。
基础形式:
watch com.demo.OrderService create params returnObj throwExp -x 2
常见参数:
| 参数 | 含义 |
|---|---|
params |
方法参数 |
returnObj |
返回值 |
throwExp |
抛出的异常 |
target |
当前对象 |
-x |
展开层级 |
-n |
匹配次数 |
条件过滤:
watch com.demo.OrderService create params returnObj 'params[0] > 1000' -x 2 -n 3
这表示只观察第一个参数大于 1000 的调用,最多 3 次。
注意:打印过大的对象可能拖慢请求,也可能刷爆终端。生产上要加条件和次数。
24.4 trace 耗时
trace 用于查看调用链中每层方法的耗时。
trace com.demo.OrderService create -n 5 --skipJDKMethod false
输出中可以看到每个子调用的耗时占比。适合回答:一个接口慢,到底慢在 SQL、RPC、序列化还是自身计算。
常用技巧:
# 只看超过 100ms 的调用
trace com.demo.OrderService create '#cost > 100' -n 5
限制:
- 只能看到匹配类的方法链;
- 方法增强有开销;
- 异步和动态代理可能需要换切点;
- 线程切换会导致栈不连续;
- 极高频方法要严格限制次数。
24.5 stack 查看调用来源
stack 输出方法被调用时的调用栈:
stack com.demo.OrderService create -n 5
适合定位:
- 某个方法被谁调用;
- 意外路径从哪里进入;
- 缓存穿透来源;
- 定时任务触发链。
如果调用非常频繁,同样要加过滤条件。
24.6 tt 时间隧道
tt 可以记录方法调用,之后回看参数、返回值和调用栈。
tt -t com.demo.OrderService create -n 10
tt -l
tt -i 1000
tt -i 1000 -p
含义:
| 命令 | 用途 |
|---|---|
-t |
记录调用 |
-l |
列出记录 |
-i |
查看指定编号 |
-p |
重放调用 |
重放请求可能再次写数据库或调用下游,生产环境必须确认幂等和安全。
24.7 热更新能力
Arthas 支持 retransform 加载修改后的 class,但热更新不适合作为常规发布方式。
风险:
- 只替换方法体,不能随意改变类结构;
- 与下一次正式发布可能不一致;
- 造成“线上行为和代码仓库不一致”;
- 增强残留可能影响性能;
- 审计和回滚困难。
更稳妥的用法是:热更新只作为极端应急手段,操作前保存证据,操作后尽快正式发布等价代码。
24.8 排查 CPU 高
步骤:
1. dashboard 观察 CPU 和线程
2. thread -n 5 找高 CPU 线程
3. 查看线程栈
4. trace 或 profiler 定位热点方法
5. jad 查看线上类是否与预期一致
6. 结合日志和监控确认
示例:
dashboard
thread -n 5
thread <thread-id>
trace com.demo.TaskService execute '#cost > 100' -n 5
如果高 CPU 是 GC 线程,应转向 GC 日志和堆分析,而不是业务方法。
24.9 排查接口偶发慢
建议流程:
1. 确认入口类和方法
2. trace 加成本过滤
3. watch 保存异常请求参数
4. 检查 SQL、RPC、锁、线程池
5. 对比正常和异常调用
6. 用业务日志补充时间线
示例:
trace com.demo.OrderController detail '#cost > 200' -n 10
watch com.demo.OrderController detail params returnObj throwExp -x 2 -n 10
thread --state BLOCKED
偶发问题要先拿到样本,再缩小范围。
24.10 安全与治理
生产使用建议:
- 通过跳板机或运维平台执行;
- 记录操作审计;
- 敏感字段脱敏;
- 限制
-n和条件; - 用完执行
stop; - 不长期保留方法增强;
- 灰度实例操作;
- 避免在无降级能力的核心链路随意 watch 大对象。
本章小结
Arthas 能在不重启 JVM 的情况下观察线程、方法、参数、返回值、调用链和类加载信息,是定位线上疑难问题的利器。watch、trace、stack、tt 是核心命令,但都应加条件、次数和时长限制。生产使用要重视权限、审计、敏感数据和释放增强。
思考题
watch和日志埋点各有什么优劣?- 为什么
trace需要加#cost条件? thread -b能解决什么问题?tt -p在生产中有什么风险?- 使用 Arthas 后为什么要执行
stop?