Arthas 实战:线上诊断的"瑞士军刀"(工具篇)
环境:CentOS 7 / JDK 17 / Arthas 4.3.3
定位:前面 8 篇是"手工排查练内功",本篇是"工具提效"——同一批病例,换 Arthas 再诊断一遍
系列:CPU 100% / 锁竞争 / 频繁 Young GC / 切换风暴 / 下游慢 / 池耗尽 / 死锁 / OOM
关键词:attach、thread -n、thread -b、jad、watch、ognl、heapdump
一、Arthas 是什么?为什么生产敢用?
阿里开源的 Java 诊断工具,核心能力:不重启、不改代码,attach 到运行中的 JVM 上做诊断。
生产敢用的三个理由:
- attach 机制:通过 JVMTI 把 agent 挂进目标 JVM(和 jstack/jmap 同一套机制),不需要重启服务
- 字节码增强可还原:
watch/trace是临时增强目标方法的字节码,reset一键还原类 - 只读为主:绝大多数命令只观测不修改(ognl 例外,能调方法,慎用)
注意:dashboard 里能看到
arthas-NettyHttpTelnetBootstrap等线程——Arthas attach 后是"住进"目标 JVM 的,它的线程也会出现在诊断结果里(观察者效应)。
二、上手:下载、attach、退出
wgethttps://arthas.aliyun.com/arthas-boot.jarjava-jararthas-boot.jar# 列出 Java 进程,输入【序号】(不是 PID!)| 操作 | 命令 | 效果 |
|---|---|---|
| 断开但 agent 留在 JVM | quit/exit | 下次 attach 更快,但 agent 常驻 |
| 完全卸载 agent | stop | 不留痕迹,生产用完推荐 |
纪律:必须用和目标进程相同的用户启动 arthas-boot,JDK 大版本别太老。
三、手工 vs Arthas 对照表(本篇灵魂)
| 手工流程(前 8 篇) | Arthas | 场景 |
|---|---|---|
top -H→printf %x→jstack grep nid | thread -n 3一条搞定 | A1 CPU 高 |
jstack状态统计找 BLOCKED → grep 锁地址 → 找持锁者 | thread -b自动揪持锁者 | B1 锁竞争 |
jstack | grep State | sort | uniq -c | thread --state BLOCKED(标题行直接印统计) | 状态分布 |
jstat -gc 1000 10两次采样算差值 | dashboard实时面板 | A2 GC |
jmap -histo/jmap -dump | memory/heapdump | B4 内存 |
| 翻 jar 包确认代码版本 | jad反编译线上类 | 版本核对 |
| 加日志→发版→复现 | watch/trace免日志观测 | 方法级排查 |
四、实战命令详解(全部真实演练)
① dashboard——综合面板(替代 top+jstat+jstack 三窗口)
- 线程区:
main线程 RUNNABLE 99.75% 直接登顶(不用转 16 进制) - Memory 区:heap/eden/old_gen/metaspace 实时水位 + GC 次数耗时
- Runtime 区:load、核数、JVM 版本
② thread -n 3——CPU 排查一条命令
"main" Id=1 cpuUsage=100.0% deltaTime=200ms time=873782ms RUNNABLE at com.jvm.cpu.CpuHighDemo$DeadLoop.main(CpuHighDemo.java:32)cpuUsage + deltaTime:采样窗口内的瞬时占用time:累计 CPU 时间(等价 jstack 的cpu=)- 直接打印完整堆栈,栈顶就是那行死循环
③ thread -b——锁竞争的"自动破案"
推荐动线:先 dashboard 定方向,再 thread -b 抓凶手。
第一步,dashboard线程区一眼定调——STATE 列一片红色BLOCKED,且每个 Worker 的 %CPU 都接近 0:
读图要点:状态红 + CPU 低 = 没人干活全在排队(等锁/等池子系)。如果是 A1 死循环,这里应该是某个线程绿色 RUNNABLE + 99% CPU。一个 dashboard 就把"干活系"和"等待系"分开了。
第二步,thread -b精准定位持锁者:
"Worker-15" Id=28 TIMED_WAITING at java.lang.Thread.sleep(Native Method) at ...LockContention.lambda$main$0(CpuHighDemo.java:122) - locked java.lang.Object@243ef36b <---- but blocks 18 other threads!持锁者 + 锁地址 + 受害规模,三合一输出——手工时代这是半篇博客的排查量。
④ jad——反编译线上代码(发错包的克星)
jad com.jvm.cpu.CpuHighDemo$LockContention输出头部两行隐藏情报:
ClassLoader: +-AppClassLoader ... ← 谁加载的(类冲突/元空间问题用) Location: /home/lhadmin/jvm-demo/target/classes/ ← 从哪个物理路径加载的面试题"怎么确认线上代码版本"的标准答案:jad反编译正在运行的类,和源码对照。
⑤ watch——免日志观测方法(布控式)
watch com.jvm.cpu.CpuHighDemo$LockContention lambda$main$0 '{params,returnObj}' -x 2 -n 3 # Affect(class count: 1, method count: 1) cost in 110 ms, listenerId: 1{params,returnObj,throwExp}:观测入参/返回值/异常,-x 2展开深度,-n 3抓 3 次自动停- 配套:
trace(方法内调用链逐跳耗时,定位慢在哪一行)、monitor -c 5(方法调用统计)、stack(谁调用了这个方法) - 用完
reset还原被增强的类
⑥ ognl——直接读写运行时对象
ognl '@com.jvm.cpu.CpuHighDemo$LockContention@counter.get()' # @Integer[625634] ← 静态变量实时值踩坑实录(JDK 9+ 模块墙):
ognl '@...@counter' # 直接读对象 → 报错: InaccessibleObjectException: module java.base does not "opens java.util.concurrent.atomic"OGNL 默认反射序列化整个对象(含私有字段),JDK 9+ 模块化拦下。解法:不读字段,改调 public 方法.get()——这也是生产环境--add-opens参数存在的意义。
⑦ heapdump——一条命令导堆(但生产纪律不变)
heapdump /tmp/arthas-dump.hprof # Heap dump file created两个必须说清的点:
- 它只是"导出变简单了":Arthas 的 heapdump 本质就是
jmap -dump换皮(底层同一个 HotSpot dumpHeap 调用),同样 STW、文件同样≈堆大小——别以为换了工具就没代价了。生产环境依然要遵守第 8 篇的纪律:低峰期或摘流量后再导;只想粗判先用memory(等价 jmap -histo,不触发 FGC) - 分析还是 MAT/VisualVM 的活:heapdump 只负责把堆"搬出来",支配树、Leak Suspects、引用链分析仍在 MAT/VisualVM 里做,完整流程见第 8 篇
一句话:Arthas 优化的是"怎么拿出来",不是"要不要 STW",更不替代"怎么分析"。
五、其他高频命令速查
| 命令 | 干什么 | 面试场景 |
|---|---|---|
jvm | JVM 整体信息 | 快速摸底 |
vmoption | 查看/动态改 JVM 参数 | "线上能临时开 GC 日志吗"→ 能 |
logger | 动态改日志级别 | 不重启开 DEBUG |
getstatic 类名 字段名 | 看静态字段(ognl 的简便版) | 读配置开关 |
profiler start/stop | async-profiler 火焰图 | CPU/内存分配热点,性能分析压轴 |
sc -d 类名 | 类的加载信息 | 类冲突排查 |
tt -t 类 方法 | 记录方法调用时空隧道,可回放 | 疑难偶发问题 |
六、面试 60 秒话术
“线上诊断我用 Arthas,它通过 attach 机制挂进 JVM,不用重启。CPU 高用
thread -n直接拿热点线程堆栈,锁问题thread -b自动找持锁者;确认代码版本用jad反编译;方法级排查用watch/trace免日志观测入参返回值和逐跳耗时;运行时的静态值用ognl读;堆问题heapdump导出来 MAT 分析。增强类用完reset还原,退出用stop卸载 agent 不留痕迹。手工的 top/jstack/jstat 命令链我也熟——那是理解原理,Arthas 是生产提效。”
口诀:热点 -n、找锁 -b、版本 jad、观测 watch、读值 ognl、导堆 heapdump;attach 来、stop 走,reset 还原不留痕。