1. Arthas 是什么
Arthas 是阿里开源的 Java 诊断工具。它以 Java Agent 的方式附着到目标 JVM,在不修改业务代码、不重启服务的前提下,帮助开发者查看线程、内存、类加载、方法调用、入参、返回值、异常和执行耗时。
你是不是也有遇到过这些问题:
- 某个接口突然变慢,慢在哪个方法?是不是死锁了?
- 某个方法的入参到底是什么?
- 线上运行的代码和本地代码是否一致?
- 某个异常是谁抛出的?
- CPU 为什么突然飙高,是什么原因造成的呢?
- 我写的代码没有执行,是部署分支不对,还是我压根没提交呢?
那arthas刚好就是解决这些问题的,简单来说,日志告诉你“发生过什么”,Arthas 让你看到“此刻正在发生什么”。
2. Arthas 的工作原理
Arthas 会通过 Java 的 Attach API 连接到指定 JVM,并利用 Instrumentation 对目标类进行增强。

因此,它能观察方法执行过程,但也意味着线上使用必须谨慎:范围要小、次数要有限制、观察结束后要退出或恢复增强。
3.安装与启动
在上面我们了解了它是什么,以及怎么工作的,现在我们就来安装启动实操一下。
安装:curl -O https://arthas.aliyun.com/arthas-boot.jar
启动:java -jar arthas-boot.jar
在自己需要安装的地方,打开终端命令窗口执行安装指令

注意:然后启动的时候要有一段jvm进程是在运行的
我这边为了简单做个demo,已经把代码粘贴到这边了
import java.lang.management.ManagementFactory;
import java.time.LocalTime;
import java.util.concurrent.ThreadLocalRandom;
/**
* A small long-running JVM for practicing Arthas commands.
*
* Compile: javac ArthasDemoApplication.java
* Run: java ArthasDemoApplication
*/
public class ArthasDemoApplication {
public static void main(String[] args) throws InterruptedException {
String processName = ManagementFactory.getRuntimeMXBean().getName();
System.out.println("Arthas demo started. JVM process: " + processName);
System.out.println("Keep this window open, then attach Arthas from another terminal.");
OrderService orderService = new OrderService();
int sequence = 1;
while (true) {
Order order = new Order("order-" + sequence, 99 + sequence);
try {
OrderResult result = orderService.createOrder(order);
System.out.println(LocalTime.now() + " success: " + result);
} catch (IllegalStateException exception) {
System.out.println(LocalTime.now() + " failed: " + exception.getMessage());
}
sequence++;
Thread.sleep(1000);
}
}
}
class OrderService {
private final InventoryService inventoryService = new InventoryService();
private final PaymentService paymentService = new PaymentService();
public OrderResult createOrder(Order order) {
validate(order);
inventoryService.reserve(order);
int payableAmount = calculatePayableAmount(order);
String paymentId = paymentService.pay(order, payableAmount);
return new OrderResult(order.getId(), paymentId, payableAmount);
}
private void validate(Order order) {
if (order.getAmount() <= 0) {
throw new IllegalArgumentException("amount must be positive");
}
}
private int calculatePayableAmount(Order order) {
return order.getAmount() * 9 / 10;
}
}
class InventoryService {
public void reserve(Order order) {
int number = order.getNumber();
if (number % 5 == 0) {
sleep(1500); // Deliberately slow: useful for trace.
}
if (number % 7 == 0) {
throw new IllegalStateException("inventory is unavailable for " + order.getId());
}
}
private void sleep(long milliseconds) {
try {
Thread.sleep(milliseconds);
} catch (InterruptedException exception) {
Thread.currentThread().interrupt();
}
}
}
class PaymentService {
public String pay(Order order, int payableAmount) {
if (ThreadLocalRandom.current().nextInt(10) == 0) {
throw new IllegalStateException("payment gateway timeout for " + order.getId());
}
return "pay-" + order.getNumber() + "-" + payableAmount;
}
}
class Order {
private final String id;
private final int amount;
Order(String id, int amount) {
this.id = id;
this.amount = amount;
}
String getId() {
return id;
}
int getAmount() {
return amount;
}
int getNumber() {
return Integer.parseInt(id.substring("order-".length()));
}
}
class OrderResult {
private final String orderId;
private final String paymentId;
private final int payableAmount;
OrderResult(String orderId, String paymentId, int payableAmount) {
this.orderId = orderId;
this.paymentId = paymentId;
this.payableAmount = payableAmount;
}
@Override
public String toString() {
return "OrderResult{orderId='" + orderId + "', paymentId='" + paymentId
+ "', payableAmount=" + payableAmount + "}";
}
}
终端打开,到这个代码的目录下,编译和启动这个代码,他会持续的运行,并打印 JVM 进程号
cd D:\Self-Media
javac ArthasDemoApplication.java
java ArthasDemoApplication

保持这个窗口不关闭,另开一个窗口,启动arthas
java -jar arthas-boot.jar

可以看到1和2两个进程,第一个就是我们的demo,运行成功如下:

4. 最重要的命令
我们可以输入 help ,可以查看有哪些指令
然后我们来介绍几个比较重要和常用的指令
| 命令 | 一句话作用 | 什么时候用 |
|---|---|---|
dashboard | 实时看板,看CPU、内存、 线程 | 一上来就用,看整体有没有异常 |
thread | 看线程栈 | 定位CPU飙高(thread -n 3)或死锁(thread -b) |
jad | 反编译类 | 确认线上代码是不是最新版本 |
watch | 看方法的入参、返回值、异常 | 接口返回错或没日志时,抓现场 |
trace | 看方法内部调用链路的耗时 | 接口慢,查瓶颈在哪一步 |
ognl | 执行表达式,查看/修改静态变量 | 查配置开关、改线上开关(谨慎) |
profiler | CPU性能分析 | 生成火焰图,定位CPU热点 |
tt | 记录方法调用 | 回放和分析历史调用 |
5. 三个核心命令:watch、trace、tt
5.1 watch:看入参、返回值和异常
watch OrderService createOrder '{params, throwExp}' -e -x 2 -n 5
参数含义:
params:方法参数returnObj:返回值throwExp:抛出的异常-x 2:对象展开层级,避免输出过深-n 5:最多采集 5 次,线上必须限制次数
5.2 trace:定位慢调用
接口变慢时,不要先猜数据库或网络问题,先追踪真实方法路径:
trace OrderService createOrder -n 5
输出会显示调用树及每个节点耗时。

5.3 tt:记录并分析调用现场
tt(Time Tunnel)会保存一次方法调用现场,适合偶发异常或难以复现的问题。
tt -t com.example.order.OrderService createOrder
查看已经记录的数据:
tt -l
查看指定记录的入参、返回值或异常:
tt -i 1000
线上使用 tt 时要注意:记录对象会占用内存,必须控制记录范围和次数,排查结束后及时清理。
6. profiler 指令生成火焰图
Arthas 的 profiler 命令底层依赖 async-profiler。当前环境下,该功能只支持 Linux 和 macOS,Windows 不能使用。
火焰图适合分析:
- CPU 持续升高,定位最消耗 CPU 的调用链
- 接口执行慢,分析 CPU 密集型代码
- 大量对象创建,定位内存分配热点
- 线程阻塞,分析锁竞争或等待调用
不过需要注意:不同问题应使用不同的采集事件。
# CPU 火焰图
profiler start --event cpu# 等待采集一段时间
profiler status# 停止并生成 HTML 文件
profiler stop --file /tmp/cpu-flamegraph.html

也可以直接指定采集时长:
profiler start --event cpu --duration 120
采集 120 秒后,文件会自动生成。
把生成的 HTML 文件复制到自己的电脑上,然后用浏览器打开。

不同事件的用途:
# CPU 消耗
profiler start --event cpu# 网络、锁、sleep 等等待
profiler start --event wall# 对象分配热点
profiler start --event alloc# 锁竞争
profiler start --event lock
事件是否可用取决于当前 Arthas 和 async-profiler 版本。
需要特别说明:
- CPU 火焰图不能直接证明 GC 频繁
alloc火焰图适合定位大量对象创建wall火焰图适合分析线程等待trace更适合分析某一个接口的单次调用耗时
7. 火焰图怎么看
普通火焰图中:
- 横向宽度:该方法及其子调用占用的采样数量
- 纵向高度:调用栈深度
- 越宽:采样占比越高
- 越往上:调用层级越深
- 底部:调用方或线程入口
- 顶部:当前正在执行的方法
例如:
main
└── OrderService.createOrder
└── PaymentService.pay
└── JsonSerializer.serialize
如果 JsonSerializer.serialize 这一块很宽,说明采样期间大量 CPU 时间消耗在 JSON 序列化相关调用上。
注意,火焰图横轴通常不是时间轴,左右位置没有特殊含义,重点看色块的宽度。

1814

被折叠的 条评论
为什么被折叠?



