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:离线安装(无网络环境)
  1. 下载离线包:https://arthas.aliyun.com/download/latest_version?mirror=aliyun
  2. 上传到服务器,解压后执行:
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。

六、核心总结

  1. 核心流程
    • 安装启动 → 选择进程 → 用 dashboard/thread 定位问题方向 → 用 watch/trace/jad 深入排查 → 用 redefine 热修复;
  2. 高频场景
    • CPU 高:dashboard → thread → trace;
    • 接口异常:watch(入参/出参/异常);
    • 代码验证:jad;
    • 内存问题:jvm → heapdump;
  3. 避坑关键
    • 线上操作优先用「只读命令」(dashboard/thread/jad),慎用 redefine;
    • 长时间监控需后台执行,避免阻塞会话;
    • 热更新仅用于小修复,大变更需走发布流程。

Arthas 是线上问题排查的「瑞士军刀」,无需侵入代码即可快速定位绝大多数 Java 应用问题,核心是「先定位范围(dashboard/thread),再精准排查(watch/trace),最后按需修复(redefine)」。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐