工程实践 / 公开文章

Arthas 阿尔萨斯

发布于 2026年8月11日18 个章节

Arthas 阿尔萨斯

18 个章节

Java 应用在线诊断工具 Arthas 的背景、核心概念和常用命令记录。

  • #Java
  • #Arthas

Arthas 阿尔萨斯

1. 背景与目标

技术背景

Arthas是阿里巴巴开源的一款Java诊断工具,旨在解决生产环境中Java应用的问题排查难题。在传统的Java应用运维中,当遇到CPU飙升、内存溢出、线程阻塞等问题时,开发者通常需要使用jps、jstack、jmap、jhat等JDK自带工具进行诊断,过程繁琐且效率低下。

Arthas的出现彻底改变了这一现状,它提供了一个统一的命令行界面,集成了大部分JDK诊断工具的功能,能够在不修改代码、不重启服务的情况下,实时监控和诊断运行中的Java应用。

解决的问题和应用场景

  1. 类加载问题诊断:快速定位类从哪个jar包加载,解决ClassNotFoundException和NoClassDefFoundError
  2. 代码执行问题:确认修改的代码是否被执行,避免因分支错误或未提交导致的问题
  3. 性能瓶颈分析:定位方法执行耗时长的原因,生成火焰图分析热点
  4. 线上调试困难:无需加日志重新发布,直接在线调试生产环境
  5. 死锁和线程阻塞:快速发现和定位线程死锁、阻塞问题
  6. 内存泄漏检测:监控JVM内存使用情况,发现内存泄漏点
  7. 动态代码修改:无需重启服务,热更新类文件修复紧急问题

2. 核心概念和底层原理

核心概念

  1. Attach机制:Arthas通过VirtualMachine.attach()方法将自身注入到目标Java进程中
  2. 字节码增强:利用ASM等字节码操作库,在运行时动态修改类的字节码以插入监控逻辑
  3. 类隔离:使用自定义ClassLoader防止Arthas的类与业务类冲突
  4. 命令系统:提供丰富的命令集合,覆盖各种诊断场景

底层原理

Arthas的工作原理可以分为以下几个步骤:

  1. 进程连接:通过Java VirtualMachine API连接到目标Java进程
  2. Agent注入:将Arthas的Agent模块注入到目标JVM中
  3. 字节码织入:使用ASM等工具在目标类的方法中织入监控代码
  4. 命令执行:用户通过命令行发送指令,Arthas解析并执行相应操作
  5. 结果返回:将诊断结果以友好的方式展示给用户
// 简化的Arthas工作流程示意图
// 1. 用户启动Arthas并选择目标进程
// 2. Arthas通过Attach API连接目标JVM
// 3. 注入Agent到目标JVM
// 4. 用户执行诊断命令(如trace)
// 5. Arthas使用ASM修改目标类字节码,插入监控逻辑
// 6. 目标方法执行时收集监控数据
// 7. 将结果返回给用户界面

技术优势

  1. 无侵入性:无需修改应用代码,不重启服务
  2. 实时性:在线诊断,实时反馈结果
  3. 全面性:覆盖性能分析、问题定位、动态修改等多个维度
  4. 易用性:命令行交互,丰富的Tab自动补全

3. 常用命令和使用方法

安装和启动

# 下载arthas-boot.jar
curl -O https://arthas.aliyun.com/arthas-boot.jar

# 启动Arthas
java -jar arthas-boot.jar

# 使用阿里云镜像加速下载(可选)
java -jar arthas-boot.jar --repo-mirror aliyun --use-http

基础命令

# 查看帮助信息
help

# 查看Arthas版本
version

# 查看当前会话信息
session

# 清屏
cls

# 查看命令历史
history

# 退出当前连接(Arthas仍在运行)
quit

# 停止Arthas服务
stop

JVM相关信息命令

# 查看JVM实时运行状态
dashboard

# 查看JVM信息
jvm

# 查看JVM系统属性
sysprop

# 查看环境变量
sysenv

# 查看JVM选项
vmoption

# 查看类的静态属性
getstatic

# 查看内存信息
memory

# 查看MBean信息
mbean

# 查看Perf Counter信息
perfcounter

# 执行GC
vmtool --action forceGc

类和类加载器相关命令

# 查看已加载的类信息
sc -d com.example.*

# 查看类的方法信息
sm com.example.MyClass

# 反编译已加载类的源码
jad com.example.MyClass

# 查看类加载器继承树
classloader

# dump已加载类的bytecode
dump com.example.MyClass

# 内存编译.java文件为.class文件
mc /tmp/MyClass.java

# 加载外部的.class文件到JVM中(redefine)
redefine /tmp/MyClass.class

# 加载外部的.class文件到JVM中(retransform)
retransform /tmp/MyClass.class

监控和跟踪命令

# 方法执行监控
monitor -c 5 com.example.MyClass myMethod

# 输出方法被调用的调用路径
stack com.example.MyClass myMethod

# 方法内部调用路径,并输出方法路径上的每个节点上耗时
trace com.example.MyClass myMethod

# 跟踪方法执行路径并过滤耗时超过100ms的调用
trace com.example.MyClass myMethod '#cost > 100'

# 方法执行数据观测
watch com.example.MyClass myMethod '{params, returnObj}' -x 2

# 记录方法执行数据的时空隧道
tt -t com.example.MyClass myMethod

线程相关命令

# 查看线程信息,支持多种参数
thread

# 查看阻塞线程
thread -b

# 查看指定线程ID的信息
thread 1

# 查看Top N线程
thread -n 5

thread -n 3				#打印最忙的3个线程堆栈信息
thread -i 1000			# 统计最近1000ms内的线程CPU时间
thread -n 3 -i 1000			# 列出1000ms内最忙的3个线程栈

Profiler和火焰图

# 使用async-profiler进行采样
profiler start

# 停止采样并生成火焰图
profiler stop --format html

# 查看采样状态
profiler status

快速开始

  1. 先下载一个demojar包 wget https://arthas.aliyun.com.math-game.jar, 并启动 java -jar math-game.jar

  2. 下载arthas curl -O https://arthas.aliyun.com/arthas-boot.jar 另外窗口启动 java -jar arthas-boot.jar

  3. 启动之后显示当前正在运行的java进程

    image-20220402152833237

  4. 输入2 , 显示该进程信息, 此时已经进入了arthas的 bash模式

    image-20220402153125889

  5. 使用arthas键入命令即可, 退出bash 使用 exitquit , 完全停止arthas使用 stop

dashboard

当前系统的实时数据面板,按 ctrl+c 退出

dashboard

数据说明

  • ID: Java级别的线程ID,注意这个ID不能跟jstack中的nativeID一一对应。
  • NAME: 线程名
  • GROUP: 线程组名
  • PRIORITY: 线程优先级, 1~10之间的数字,越大表示优先级越高
  • STATE: 线程的状态
  • CPU%: 线程的cpu使用率。比如采样间隔1000ms,某个线程的增量cpu时间为100ms,则cpu使用率=100/1000=10%
  • DELTA_TIME: 上次采样之后线程运行增量CPU时间,数据格式为
  • TIME: 线程运行总CPU时间,数据格式为分:秒
  • INTERRUPTED: 线程当前的中断位状态
  • DAEMON: 是否是daemon线程

JVM内部线程

Java 8之后支持获取JVM内部线程CPU时间,这些线程只有名称和CPU时间,没有ID及状态等信息(显示ID为-1)。 通过内部线程可以观测到JVM活动,如GC、JIT编译等占用CPU情况,方便了解JVM整体运行状况。

  • 当JVM 堆(heap)/元数据(metaspace)空间不足或OOM时,可以看到GC线程的CPU占用率明显高于其他的线程。
  • 当执行trace/watch/tt/redefine等命令后,可以看到JIT线程活动变得更频繁。因为JVM热更新class字节码时清除了此class相关的JIT编译结果,需要重新编译。

JVM内部线程包括下面几种:

  • JIT编译线程: 如 C1 CompilerThread0, C2 CompilerThread0
  • GC线程: 如GC Thread0, G1 Young RemSet Sampling
  • 其它内部线程: 如VM Periodic Task Thread, VM Thread, Service Thread

官方文档

arthas官方文档