arthas 是线上 java 进程的实时诊断“手术刀”,核心连入命令为 java -jar arthas-boot.jar;它自动扫描本地 java 进程,支持 docker 内进程(需进入容器操作),watch 用于观察方法结果,trace 用于分析调用链耗时,ognl 需指定 classloader 才能访问应用类,诊断后务必 quit 或 shutdown 清理 agent。

Arthas 不是“远程调试器”,也不是“JVM监控面板”,它是你线上 Java 进程出问题时,能直接连上去、实时看、动态改、马上验证的手术刀。
怎么连上正在跑的 Java 进程
核心就一条命令:java -jar arthas-boot.jar。它会自动扫描本机所有 Java 进程,列出 PID 和主类,选一个回车就行。别手贱去翻文档找 as.sh 或 arthas-client —— 那些是旧版或特殊场景用的,arthas-boot.jar 是当前唯一推荐入口。
- 如果进程在 Docker 里,得先
docker exec -it <container> /bin/bash</container>,再把arthas-boot.jar拷进去(或挂载卷),不能直接在宿主机上扫到容器内进程 - 非 root 用户启动的 Java 进程,
arthas-boot.jar可能因权限不足 attach 失败,报错Unable to open socket file,这时候要么切到对应用户执行,要么加 JVM 参数-Djdk.attach.allowAttachSelf=true(JDK 8u191+) - 连上后提示符变成
[arthas@12345]$,这个12345就是目标进程 PID,不是 Arthas 自己的 PID
watch 和 trace 到底该用哪个
watch 看的是方法执行后的结果(返回值、入参、异常),trace 看的是方法内部调用链耗时。两者定位问题的方向完全不同:前者适合“结果不对”,后者适合“怎么这么慢”。
-
watch com.example.service.UserService login '{params,returnObj,throwExp}' -n 5:只抓最近 5 次调用的入参、返回值、异常,不卡线程 -
trace com.example.controller.OrderController createOrder:默认只显示耗时 > 1ms 的调用,想看全部得加-n 5 --skipJDK(跳过 JDK 内部方法,不然全是String.valueOf) - 别对高频方法(比如
toString()、hashCode())用trace,容易把目标进程拖垮;watch也建议加-n限流,否则日志刷屏还可能 OOM
为什么 ognl 执行老是报 class not found
Arthas 的 ognl 命令是在目标 JVM 的上下文中执行的,但它默认只加载 bootstrap 和 system classloader 的类,应用自己的类(比如 Spring Bean、自定义工具类)得手动指定 classloader。
立即学习“Java免费学习笔记(深入)”;
- 先用
sc -d *User*查到类全名和对应的 ClassLoader hash,比如输出里有classLoaderHash: 0x3f4a76c5 - 再用
ognl -c 0x3f4a76c5 '@com.example.util.DateUtils@now()',-c参数必须带,否则找不到类 - Spring Bean 不能直接
@Autowired,得先通过ApplicationContext获取:ognl -c 0x3f4a76c5 '#context=@org.springframework.context.ApplicationContext@getBean("userMapper")' - OGNL 表达式里别写复杂逻辑,它不支持 lambda、try-catch,连三元运算符都容易解析失败
退出和清理比你想象中更重要
Arthas 不是“连上就完事”,它会在目标 JVM 中注入 agent,长期挂着可能影响 GC、占用内存、甚至干扰某些字节码增强框架(比如 Byte Buddy)。每次诊断完,务必执行 quit 或 shutdown。
-
quit:断开当前终端连接,agent 还在 JVM 里,下次还能连 -
shutdown:彻底卸载 agent,释放资源,JVM 恢复“干净”状态 - 如果终端异常断开(比如网络中断、Ctrl+C),Arthas 通常能自动清理,但遇到 JDK 8u191 以下版本或某些国产 JDK,可能残留 agent,得重启应用
- 别在生产环境反复
attach/detach同一个进程——有些老版本 JDK 有 attach 次数限制,试多了会直接拒绝后续连接
真正难的从来不是“怎么用命令”,而是判断哪条命令在哪个时机下不会让系统更糟。连之前先看 GC 日志,watch 之前先 sc 确认类存在,ognl 之前先 -c 指定 classloader——这些不是步骤,是条件反射。









