Arthas 处理线上问题(实战指南:从安装到核心场景)
·
Arthas 是阿里开源的 Java 诊断工具,无需修改代码/重启应用,即可在线排查「性能瓶颈、线程阻塞、类加载异常、接口耗时」等线上问题。
一、环境准备(快速安装&启动)
1. 安装 Arthas(支持 Linux/Mac/Windows)
方式1:一键安装(推荐)
# 下载并启动 arthas-boot.jar(自动匹配本地 Java 进程)
curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar
方式2:离线安装(无网络环境)
- 下载离线包:https://arthas.aliyun.com/download/latest_version?mirror=aliyun
- 上传到服务器,解压后执行:
cd arthas-bin
./arthas-boot.jar
2. 选择目标进程
执行 java -jar arthas-boot.jar 后,会列出当前服务器的 Java 进程,输入序号选择要诊断的应用(如序号 1):
* [1]: 12345 com.example.Application # 目标应用(PID=12345)
[2]: 67890 org.apache.tomcat.startup.Bootstrap
请输入序号选择要诊断的进程:1
3. 核心交互说明
- 成功启动后进入 Arthas 命令行,支持「命令补全(Tab)、历史记录(↑↓)、帮助(help 命令)」;
- 退出 Arthas:
quit(退出当前会话,不影响应用)/stop(完全停止 Arthas 服务); - Web 控制台(可选):默认开启 8563 端口,访问
http://服务器IP:8563可通过网页操作。
二、核心命令速查(高频使用)
| 命令 | 核心用途 | 常用参数/示例 |
|---|---|---|
dashboard |
实时监控(线程、内存、CPU、GC) | dashboard -i 2000(2秒刷新一次) |
thread |
线程诊断(死锁、阻塞、CPU 高) | thread 123(查看线程ID=123)、thread -n 5(Top5 耗时线程) |
jad |
反编译类(验证线上代码是否生效) | jad com.example.service.UserService |
watch |
监控方法入参/出参/异常 | watch com.example.controller.UserController getUser "{params,returnObj}" -x 2 |
trace |
方法调用链路耗时(定位慢方法) | trace com.example.service.OrderService createOrder |
stack |
查看方法调用栈(定位谁调用了该方法) | stack com.example.dao.OrderDao query |
tt |
记录/回放方法调用(复现问题) | tt -t com.example.service.PayService pay |
jvm |
查看 JVM 信息(堆、栈、GC 配置) | jvm(直接执行) |
sc |
查看类加载信息(是否加载、加载来源) | sc -d com.example.entity.User |
redefine |
热更新类(修复小问题,无需重启) | redefine /tmp/UserService.class |
三、典型线上问题排查场景(实战示例)
场景1:CPU 使用率过高(定位耗时线程/方法)
步骤1:通过 dashboard 定位高 CPU 线程
执行 dashboard,查看「ID(线程ID)、CPU%(线程CPU占比)、NAME(线程名)」列,找到 CPU 占比最高的线程(如 ID=123,CPU%=80%)。
步骤2:查看线程堆栈,定位耗时方法
# 查看线程ID=123的详细堆栈(-n 30 显示前30行)
thread 123 -n 30
输出示例(定位到 UserService.queryUser 方法耗时):
"http-nio-8080-exec-10" Id=123 RUNNABLE
at com.example.service.UserService.queryUser(UserService.java:50)
at com.example.controller.UserController.getUser(UserController.java:25)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
步骤3:trace 方法链路,定位具体耗时点
# 跟踪 queryUser 方法的调用链路,打印耗时>10ms的节点
trace com.example.service.UserService queryUser '#cost > 10'
输出示例(定位到 UserDao.selectById 耗时 500ms):
`---[500ms] com.example.service.UserService:queryUser()
`---[498ms] com.example.dao.UserDao:selectById()
场景2:接口返回异常(监控方法入参/出参/异常)
问题现象:/user/get 接口偶尔返回 null,需排查入参和返回值
# watch 命令监控方法:
# 1. 类:UserController,方法:getUser
# 2. 表达式:{params(入参), returnObj(返回值), throwExp(异常)}
# 3. -x 2:展开参数层级(默认1层,复杂对象需加大)
# 4. -e:仅捕获异常时输出
# 5. -n 10:最多输出10次
watch com.example.controller.UserController getUser "{params,returnObj,throwExp}" -x 2 -e -n 10
输出示例(定位到入参 userId=0 时返回 null):
ts=2026-03-20 10:00:00 [cost=5ms]
params: [0] # 入参 userId=0
returnObj: null # 返回值为空
throwExp: null
场景3:验证线上代码是否生效(反编译类)
问题:发布后怀疑代码未更新,验证 OrderService.createOrder 方法
# 反编译指定类(仅显示 createOrder 方法)
jad com.example.service.OrderService createOrder
输出示例(直接显示源码,对比是否为最新版本):
ClassLoader:
+-org.springframework.boot.loader.LaunchedURLClassLoader@6d03e736
Location:
file:/opt/app/order-service.jar!/BOOT-INF/classes!/
public class OrderService {
public String createOrder(Long orderId) {
// 反编译后的代码(验证是否包含最新逻辑)
if (orderId == null) {
return "error";
}
return "success";
}
}
场景4:线程死锁/阻塞(定位死锁线程)
# 一键检测死锁(arthas 自动识别)
thread -deadlock
输出示例(定位到死锁线程和锁资源):
Found one deadlock:
=====================
"thread-1":
waiting to lock monitor 0x00007f9e10006800 (object 0x000000076ab82200, a java.lang.Object),
which is held by "thread-2"
"thread-2":
waiting to lock monitor 0x00007f9e10008c00 (object 0x000000076ab82210, a java.lang.Object),
which is held by "thread-1"
场景5:热更新类(修复小问题,无需重启)
适用场景:线上小bug(如参数校验逻辑错误),需快速修复
步骤1:反编译线上类,保存到本地
jad --source-only com.example.service.UserService > /tmp/UserService.java
步骤2:修改代码(如修复参数校验逻辑)
// 本地修改 /tmp/UserService.java,修复bug
public String queryUser(Long userId) {
if (userId == null || userId <= 0) { // 新增 userId <=0 校验
return "参数错误";
}
return userDao.selectById(userId);
}
步骤3:编译修改后的类(需服务器有 javac 环境)
javac -cp /opt/app/order-service.jar!/BOOT-INF/classes/:/opt/app/lib/* /tmp/UserService.java
步骤4:热更新类到 JVM
# redefine 命令加载新的 class 文件
redefine /tmp/UserService.class
✅ 验证:调用接口,确认 bug 已修复(无需重启应用)。
场景6:JVM 内存溢出(排查堆/非堆内存)
步骤1:查看 JVM 内存使用情况
jvm
重点关注:
Heap Memory Usage:堆内存(Eden/Old/Survivor 区使用占比);Non-Heap Memory Usage:非堆内存(Metaspace 元空间);GC Collection Counts/Time:GC 次数/耗时(频繁 FullGC 需警惕)。
步骤2:导出堆快照(分析内存泄漏)
# 导出堆快照到 /tmp/heap.hprof
heapdump /tmp/heap.hprof
下载快照后,用 MAT(Memory Analyzer Tool) 分析:定位大对象(如 HashMap 未释放、大量对象堆积)。
四、进阶技巧(提升排查效率)
1. 命令后台执行(避免断开会话)
线上排查时,若需长时间监控(如 trace 耗时方法),可将命令放入后台执行:
# 后台执行 trace 命令,输出到 /tmp/trace.log
nohup trace com.example.service.OrderService createOrder > /tmp/trace.log 2>&1 &
2. 条件过滤(精准定位问题)
watch/trace 命令支持表达式过滤,仅监控符合条件的调用:
# 仅监控 userId=1001 的 getUser 调用
watch com.example.controller.UserController getUser "{params,returnObj}" -x 2 -b -s "params[0]==1001"
参数说明:
-b:方法执行前触发;-s:方法执行后触发;- 表达式:
params[0]==1001(入参第一个值等于1001)。
3. 远程连接 Arthas(跨机器诊断)
若需本地连接服务器的 Arthas(避免直接操作生产机):
# 服务器端启动 arthas,指定 IP 和端口
java -jar arthas-boot.jar --target-ip 0.0.0.0 --telnet-port 9999 --http-port 8563
# 本地客户端连接
telnet 服务器IP 9999
五、避坑要点(线上操作注意事项)
1. 禁止高危操作
redefine命令:
✅ 支持:修改方法逻辑、参数校验;
❌ 禁止:修改类结构(新增/删除字段、方法)、修改父类/接口;- 避免在高并发接口上执行
trace/monitor(可能增加应用耗时)。
2. 性能影响
- 高频命令(如
dashboard -i 100)会占用 CPU,建议刷新间隔 ≥1000ms; - 长时间执行
watch/trace会生成大量日志,需及时停止。
3. 权限问题
- 启动 Arthas 的用户需与应用进程用户一致(否则无法 attach 进程);
- 生产环境建议用非 root 用户操作(避免权限过大)。
4. 版本兼容
- Arthas 支持 JDK 6+,但部分命令(如
redefine)在 JDK 8 以上更稳定; - 若应用是 Spring Boot 可执行 jar,需确保 Arthas 版本 ≥3.0。
六、核心总结
- 核心流程:
- 安装启动 → 选择进程 → 用 dashboard/thread 定位问题方向 → 用 watch/trace/jad 深入排查 → 用 redefine 热修复;
- 高频场景:
- CPU 高:dashboard → thread → trace;
- 接口异常:watch(入参/出参/异常);
- 代码验证:jad;
- 内存问题:jvm → heapdump;
- 避坑关键:
- 线上操作优先用「只读命令」(dashboard/thread/jad),慎用 redefine;
- 长时间监控需后台执行,避免阻塞会话;
- 热更新仅用于小修复,大变更需走发布流程。
Arthas 是线上问题排查的「瑞士军刀」,无需侵入代码即可快速定位绝大多数 Java 应用问题,核心是「先定位范围(dashboard/thread),再精准排查(watch/trace),最后按需修复(redefine)」。
更多推荐



所有评论(0)