Arthas
Arthas 是阿里巴巴开源的 Java 诊断工具,无需重启应用、无需修改代码,可在生产环境动态查看类加载情况、方法参数/返回值/异常、线程栈、内存使用等,是排查线上问题的核心工具。
与 JProfiler 的区别:JProfiler 适合本地性能剖析,Arthas 适合线上动态诊断。
安装与启动
# 方式一:下载 jar 包(推荐)
curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar # 自动列出 JVM 进程,选择编号后 attach
# 方式二:一键安装脚本
curl -L https://arthas.aliyun.com/install.sh | sh
./as.sh
# 方式三:Docker 环境(attach 到容器内的 JVM)
java -jar arthas-boot.jar --target-ip 0.0.0.0启动后进入交互式 Console,输入 help 查看所有命令。
基础命令
# 查看 JVM 进程信息(已 attach 的进程)
version
# 查看系统属性
sysprop # 列出所有
sysprop java.version # 查看单个
# 查看环境变量
sysenv
sysenv JAVA_HOME
# JVM 整体运行状态(内存、GC、线程数)
jvm
# 实时仪表盘(CPU、内存、GC、线程,每隔 5s 刷新)
dashboard
# 退出 Arthas(不影响目标进程)
quit
# 完全停止 Arthas(detach 并退出)
stop类与类加载器
# 查看类的加载信息(类加载器、代码源路径)
sc com.example.service.UserService
sc -d com.example.service.UserService # 详细信息(包含字段、方法)
# 通配符搜索
sc com.example..*Service
# 反编译类(查看字节码对应的源码,确认部署版本正确)
jad com.example.service.UserService
# 反编译指定方法
jad com.example.service.UserService getUserById
# 查看类的方法列表
sm com.example.service.UserService
sm -d com.example.service.UserService getUserById # 方法详情
# 从 JVM 中导出类的 class 文件
dump com.example.service.UserServicewatch — 观察方法调用
watch 是最常用的命令,拦截方法的入参、返回值、异常,不修改代码、不重启:
# 基本语法
watch 类名 方法名 观察表达式 [条件] [-x 展开深度]
# 观察返回值(-x 2 展开两层对象)
watch com.example.service.UserService getUserById returnObj -x 2
# 同时观察入参和返回值
watch com.example.service.UserService getUserById '{params, returnObj}' -x 3
# 观察入参
watch com.example.service.OrderService createOrder '{params[0]}' -x 2
# 只观察抛出异常的调用
watch com.example.service.UserService getUserById throwExp -e
# 条件过滤:只观察第一个参数等于 1001 的调用
watch com.example.service.UserService getUserById returnObj 'params[0]==1001L'
# 观察耗时超过 200ms 的调用
watch com.example.service.OrderService processOrder '{params, returnObj, throwExp}' '#cost>200' -x 2
# 在方法入口观察(默认在方法出口)
watch com.example.service.UserService getUserById params -btrace — 方法调用链路追踪
追踪方法内部调用树及每一步耗时,快速定位哪个子方法慢:
# 追踪方法调用链
trace com.example.service.OrderService createOrder
# 设置最大追踪深度(防止链路过深)
trace com.example.service.OrderService createOrder --skipJDKMethod false -n 5
# 只追踪耗时超过 100ms 的调用
trace com.example.service.OrderService createOrder '#cost>100'输出示例:
`---ts=2024-01-15 10:23:11; thread_name=http-nio-8080-exec-1; id=xxx; is_daemon=true; ---[198ms] com.example.service.OrderService:createOrder()
+---[0ms] com.example.dao.UserDao:findById()
+---[195ms] com.example.dao.InventoryDao:checkStock() ← 慢!
`---[2ms] com.example.dao.OrderDao:save()
stack — 输出方法调用来源
查看某方法是被哪些调用路径触发的:
stack com.example.dao.UserDao findById
# 只在特定条件下触发
stack com.example.service.UserService getUserById 'params[0]==1001L'monitor — 方法调用统计
统计方法在一段时间内的调用次数、成功率、平均耗时:
# 每 10 秒统计一次
monitor com.example.service.UserService getUserById -c 10输出:
timestamp class method total success fail avg-rt(ms) fail-rate
2024-01-15 10:23 UserService getUserById 42 41 1 12.4 2.38%
tt — 时光机(记录并重放调用)
tt(TimeTunnel)记录每次方法调用的快照,事后可查询和重放:
# 开始记录(最多 100 条)
tt -t com.example.service.UserService getUserById -n 100
# 查看记录列表
tt -l
# 查看某条记录详情(INDEX 是记录编号)
tt -i 1003 -x 3
# 重放某条调用(用同样的入参再次执行)
tt -i 1003 -pognl — 动态执行表达式
在目标 JVM 中执行任意 Java 代码,无需修改源码:
# 调用静态方法
ognl "@com.example.util.ConfigUtil@getProperty('app.name')"
# 访问 Spring Bean(通过 ApplicationContext)
ognl "#ctx=@com.example.SpringContextHolder@getContext(), #ctx.getBean('userService').countAll()"
# 修改静态字段(临时调整配置,慎用)
ognl "@com.example.config.AppConfig@MAX_RETRY=5"
# 执行复杂表达式
ognl "new java.util.Date()"
ognl "@java.lang.System@currentTimeMillis()"线程诊断
# 查看所有线程(含 CPU 占用)
thread
# 查看 CPU 占用最高的 N 个线程
thread -n 5
# 打印指定线程的栈
thread 42
# 查找死锁
thread -b
# 过滤阻塞状态的线程
thread --state BLOCKED内存与 GC
# 堆内存使用概览(分代)
memory
# 触发一次 Full GC(谨慎,生产环境会暂停应用)
ognl "@java.lang.System@gc()"
# 查看 GC 统计
jvm | grep -A 10 "GARBAGE-COLLECTORS"热更新类(谨慎使用)
在不重启应用的情况下替换类的字节码(仅用于紧急修复,不可修改方法签名/字段):
# 1. 反编译查看现有代码
jad --source-only com.example.service.UserService > /tmp/UserService.java
# 2. 修改 /tmp/UserService.java
# 3. 编译(使用与目标 JVM 相同版本的 javac)
mc -c <classloader-hash> /tmp/UserService.java -d /tmp/
# 4. 重新加载
redefine /tmp/com/example/service/UserService.class热更新仅修改方法体,不能增减字段/方法,重启后失效。生产环境应走正式发布流程。
常用排查场景
| 问题 | 命令 |
|---|---|
| 接口返回值异常 | watch 观察方法出参 |
| 接口慢,不知道慢在哪 | trace 追踪调用链耗时 |
| CPU 飙高 | thread -n 5 找热点线程 + jad 看代码 |
| 内存泄漏 | memory + ognl 查堆对象 |
| 方法被意外调用 | stack 反查调用来源 |
| 确认部署版本正确 | jad 反编译对比代码 |
| 临时修改配置生效 | ognl 修改静态字段 |
| 死锁排查 | thread -b |