Arthas 是 Alibaba 开源的 Java 诊断工具,深受开发者喜爱。

当你遇到以下类似问题而束手无策时,Arthas可以帮助你解决:

  1. 这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?
  2. 我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?
  3. 遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?
  4. 线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!
  5. 是否有一个全局视角来查看系统的运行状况?
  6. 有什么办法可以监控到 JVM 的实时运行状态?
  7. 怎么快速定位应用的热点,生成火焰图?
  8. 怎样直接从 JVM 内查找某个类的实例?

以下是针对每个问题使用 Arthas 的解决方案和具体操作步骤:


1. 这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?

方法:
  • 查看类加载信息:使用 sc 命令查看类的加载路径和类加载器。
  • 检查类路径问题:确认类是否被多个版本加载或路径错误。
具体步骤:
# 查看类的加载信息(替换为你的类名)
sc com.example.YourClass

# 输出示例:
[Loaded com.example.YourClass from file:/path/to/your.jar]
解决类异常问题:
  • 如果类找不到或版本冲突,检查 sc 输出的路径是否正确。
  • 如果类被多次加载,可能需要排查依赖冲突(如 Maven/Gradle 依赖)。

2. 我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?

方法:
  • 反编译查看字节码:使用 jad 命令反编译当前类,确认代码是否生效。
  • 跟踪方法执行:使用 trace 命令确认方法是否被调用。
具体步骤:
# 反编译当前类的代码(替换为你的类名)
jad com.example.YourClass

// 输出(反编译后的代码片段):
public void saveUser(User user) {
    // 如果这里没有新代码,说明未生效
    user.setName("oldName"); // 旧代码
    // 新代码未出现,如 user.setName("newName");
}
# 跟踪方法执行(替换为你的方法)
trace com.example.YourClass yourMethod
# 跟踪方法执行:
arthas> trace com.example.UserService saveUser -n 1
# 输出(未触发):
[TRACE] com.example.UserService.saveUser(User) 
No matched method invoked during 10 seconds.
解决思路:
  • 如果反编译的代码与预期不符,说明代码未正确部署。
  • 如果 trace 未触发,说明代码路径未被调用,需检查逻辑分支。

3. 遇到问题无法线上 debug,难道只能通过加日志再重新发布吗?

方法:
  • 实时监控变量:使用 watch 命令在方法内监控变量值。
  • 动态追踪方法调用:使用 tracestack 命令分析调用链。
具体步骤:
# 监控方法参数和返回值(替换为你的方法)
watch com.example.YourClass yourMethod '{returnObj -> returnObj}'

# 输出
[INFO] watched method [process], total trigger count: 1
param0: {"userId": "123", "data": "corrupted"}
returnObj: null
cost: 15 ms


# 跟踪方法调用栈
trace com.example.YourClass yourMethod -e

# 输出
[TRACE] com.example.DataProcessor.process(Data) 
    at com.example.MainApplication.handleRequest(MainApplication.java:23)
    at com.example.HttpServer.lambda$handleRequest\$0(HttpServer.java:45)
解决思路:
  • 无需重新部署,直接在线上分析变量和调用链。
  • 结合 thread 命令查看线程状态,排查死锁或阻塞问题。

4. 线上遇到某个用户的数据处理有问题,但线上无法 debug,线下无法重现!

方法:
  • 过滤特定用户参数:使用 watch 命令结合条件表达式,只触发特定用户的数据。
  • 记录调用堆栈:使用 stack 命令捕获异常堆栈。
具体步骤:
# 监控特定用户ID的调用(假设参数是第1个)
watch com.example.YourClass yourMethod '{-> args[0]}' -c 'args[0].equals("problem_user_id")'

# 过滤特定用户ID的调用
arthas> watch com.example.UserProcessor processUser '{-> args[0]}' -c 'args[0].equals("problem_user_123")'

# 当用户id匹配
[INFO] watched method [processUser], total trigger count: 1
args[0]: problem_user_123
args[1]: {"data": "corrupted"}


# 捕获异常堆栈
stack -n 100

# 假设异常
java.lang.NullPointerException: data is null
    at com.example.UserProcessor.processUser(UserProcessor.java:32)

解决思路:
  • 通过条件表达式过滤出目标用户的调用,分析参数和执行路径。
  • 如果有异常,用 stack 查看堆栈信息定位问题。

5. 是否有一个全局视角来查看系统的运行状况?

方法:
  • 实时系统监控:使用 dashboard 命令查看 JVM 核心指标。
  • 线程状态分析:使用 thread 命令查看线程状态。
具体步骤:
# 查看实时系统指标(CPU、GC、线程等)
dashboard

# 输出实时更新
------- JVM Info -------
JVM Uptime: 1d 3h 22m 15s
CPU Usage: 85% (System), 75% (Process)
Memory: 20G/32G (Heap), 4G/8G (Non-Heap)
GC: Young GC 120 times, Old GC 5 times
Threads: 230 threads (Daemon: 150, Alive: 230)
------- ClassLoader -------
Loaded: 12,345 classes
Unloaded: 123 classes
------- Recent Exceptions -------
NullPointerException x5 in last 10s



# 查看线程状态
thread

# 输出
TID    Name                     State  Blocked by
12345  http-nio-8080-exec-10    RUNNABLE
67890  pool-1-thread-3          WAITING (parking)

解决思路:
  • dashboard 提供全局视角,快速发现 CPU/内存/GC 异常。
  • thread 可查看线程阻塞、死锁或高 CPU 消耗的线程。

6. 有什么办法可以监控到 JVM 的实时运行状态?

方法:
  • JVM 核心指标:使用 jvm 命令查看内存、GC、类加载等信息。
  • GC 分析:使用 gc 命令监控 GC 次数和耗时。
具体步骤:
# 查看 JVM 内存、GC、类加载等信息
jvm
# 输出
JVM Args: -Xms32g -Xmx32g -XX:+UseG1GC
Memory:
  Heap:
    init = 34359738368(32.0GB)
    used = 21474836480(20.0GB)
    committed = 34359738368(32.0GB)
    max = 34359738368(32.0GB)
  Non-Heap:
    init = 2555904(2.44MB)
    used = 3858328(3.68MB)
    committed = 4456448(4.25MB)
    max = 1772979712(1.65GB)
GC:
  Young Count: 120
  Young Time: 12000ms
  Old Count: 5
  Old Time: 5000ms


# 实时监控 GC 情况
gc
# 输出

GC Monitor:
  Young GC: 120 times, 12s (avg 100ms)
  Old GC: 5 times, 5s (avg 1s)

解决思路:
  • 通过 jvm 快速定位内存泄漏或类加载问题。
  • gc 命令可分析 Full GC 是否频繁,辅助调优。

7. 怎么快速定位应用的热点,生成火焰图?

方法:
  • 热点分析:使用 hotspot 命令定位 CPU 瓶颈。
  • 生成火焰图:使用 flame 命令生成火焰图。
具体步骤:
# 定位热点方法(默认采样 10 秒)
hotspot

# 输出
Total CPU(s): 120.5
Rank   Self CPU(ms)   Total CPU(ms)   Method
1      45.6           80.2           com.example.SlowService.processData()
2      30.1           30.1           java.util.zip.Deflater.deflateBytes()


# 生成火焰图(保存为 svg 文件)
flame > hotspot.svg
解决思路:
  • hotspot 输出 Top-N 的热点方法,直接定位性能瓶颈。
  • 火焰图(flame graph)可视化调用栈,快速识别嵌套调用问题。

8. 怎样直接从 JVM 内查找某个类的实例?

方法:
  • 查找类实例:使用 scobj 命令组合查找实例。
  • 统计实例数量:使用 obj -c 统计实例个数。
具体步骤:
# 查找类的所有实例(替换为你的类名)
sc -d com.example.YourClass | grep "identityHashCode"
# 输出类似:identityHashCode=123456

# 查看实例详情(替换为 identityHashCode)
obj 123456

# 输出
com.example.User@123456
  userId: 123
  name: "John Doe"
  data: {"status": "active"}


# 统计实例数量
obj -c com.example.YourClass

# 输出
Total instances of com.example.User: 15

解决思路:
  • 通过 sc -d 获取类的实例对象地址。
  • 使用 obj 查看实例的字段和引用,排查内存泄漏或状态问题。

总结

问题类型 关键命令 作用描述
类加载问题 sc 查看类加载路径和类加载器
代码未生效 jad, trace 反编译代码,跟踪方法调用
实时调试 watch, trace, stack 监控变量、方法调用和异常堆栈
用户数据问题 watch (条件表达式) 过滤特定用户数据
全局系统监控 dashboard, thread 实时查看 JVM 指标和线程状态
JVM 状态监控 jvm, gc 分析内存、GC 情况
性能热点分析 hotspot, flame 定位 CPU 瓶颈,生成火焰图
查找对象实例 sc -d, obj 查找类实例并查看详细信息

安装 Arthas:

curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar

输入 help 查看所有命令,结合实际场景灵活使用!

Logo

一站式 AI 云服务平台

更多推荐