安装与启动
可以直接下载编译后的jar包,直接java -jar 启动
curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar
常用命令
dashboard 仪表板
展示当前进程的信息
输入dashboard,按回车即可进入。
按ctrl+c可以中断执行。
参数
-i 1000 表示 间隔打印毫秒数
-n 5 运行5次
注:输入前面部分字母,按tab可以自动补全命令
-
第一部分是显示JVM中运行的所有线程:所在线程组,优先级,线程的状态,CPU的占用率,是否是后台进程等
-
第二部分显示的JVM内存的使用情况
-
第三部分是操作系统的一些信息和Java版本号
第一部分 线程
列 | 解释 |
---|---|
ID | 线程ID |
NAME | 线程名字 |
GROUP | 线程组 |
PRIORITY | 线程优先级 |
STATE | 线程当前状态 |
%CPU | CPU占比 |
DELTA_TIM | 上次采样之后线程运行增量 CPU 时间,数据格式为秒 |
TIME | 运行时间 分钟:秒 |
INTERRUPT | 中断状态 |
DEAMON | 是否是守护线程 |
第二部分 JVM
列 | 解释 |
---|---|
Memory | 内存区域 |
used | 使用 |
total | 总共 |
max | 最大 |
usage | 使用比例 |
gc | 垃圾回收相关 |
thread
thread 后跟线程id,打印线程堆栈信息
参数
-n 5 指定最忙的前五个线程并打印堆栈(会显示 cpu占比)
-b 找出当前阻塞其他线程的线程
-i 1000 表示 间隔打印毫秒数
–state {线程状态} 可以查某种状态的线程
不带参数直接执行,就是跟 dashboard 展示线程部分一致
-b 可以用于排查死锁,如下图所示
jvm
查看JVM,线程 及 系统相关信息
组名 | 列名 | 说明 |
---|---|---|
CLASS-LOADING | LOADED-CLASS-COUNT | 目前加载的类总数 |
CLASS-LOADING | TOTAL-LOADED-CLASS-COUNT | 总共加载的类总数 |
CLASS-LOADING | UNLOADED-CLASS-COUNT | 卸载的类总数 |
OPERATING-SYSTEM | OS | 操作系统 |
OPERATING-SYSTEM | ARCH | 系统架构 |
OPERATING-SYSTEM | VERSION | 版本号 |
THREAD | COUNT | 当前线程总数 |
THREAD | DAEMON-COUNT | 守护线程数 |
THREAD | PEAK-COUNT | 虚拟机启动后最大同时存在线程数 |
THREAD | STARTED-COUNT | 线程启动后一共创建了多少(包含已经释放了的) |
THREAD | DEADLOCK-COUNT | 死锁线程个数 |
FILE-DESCRIPTOR | MAX-FILE-DESCRIPTOR-COUNT | 最大文件描述符数 |
FILE-DESCRIPTOR | OPEN-FILE-DESCRIPTOR-COUNT | 已经打开的文件描述符数 |
sysprop
显示所有系统属性,也可以修改某些属性
直接 sysprop 显示全部
sysprop 后跟 key 名,显示具体某个 属性。
sysprop 后跟 key 名,再跟 value,可以修改。
sysenv
查看当前JVM的环境属性(System Environment Variables )
不可修改
vmoption
看JVM参数,也可以修改
vmoption 参数名 值
getstatic
通过getstatic命令可以方便的查看类的静态属性
getstatic 类名 属性名
ognl
OGNL语法地址
https://commons.apache.org/proper/commons-ognl/language-guide.html
参数 -X 展开层次,默认是1,不建议太深
例:
调用静态函数
ognl '@java.lang.System@out.println( "hello" )’
获取静态类的静态字段
ognl '@demo.MathGame@random'
执行多行表达式,赋值给临时变量,返回一个List
value1 调用System.getProperty 获取 java.home 属性值
value2 调用System.getProperty 获取java.runtime.name 属性值
{#value1,value2} 表示给这俩放到一个集合里
ognl '#value1=@System@getProperty("java.home"), #value2=@System@getProperty("java.runtime.name"),{#value1,value2} '
sc
查看JVM已加载的类信息,“Search-Class”的简写,这个命令能搜索出所有已经加载到JVM中的Class信息。
sc默认开启了子类匹配功能。所有当前类的子类也会被搜索出来
想要精确匹配,可以打开 optionsdisable-sub-class true 开关
参数说明
class-pattern
支持全限定名,如 com.taobao.test.AAA
也支持 com/taobao/test/AAA 这样的格式
method-pattern
方法名表达式匹配
-d
输出当前类的详细信息,包括这个类所加载的原始文件来源、类的声明、加载的ClassLoader等详细信息。如果一个类被多个ClassLoader所加载,则会出现多次
-E
开启正则表达式匹配,默认为通配符匹配
-f
输出当前类的成员变量信息(需要配合参数-d一起使用)
例:
// 模糊搜索,demo包下所有的类
sc demo .*
// 打印类的详细信息
sc -d demo.MathGame
// 打印类的详细信息,额外打印属性
sc -df demo.MathGame
sm
查看已加载类的方法信息
"Search-Method”的简写,这个命令能搜索出所有已经加载了Class信息的方法信息。sm命令只能看到由当前类所声明(declaring)的方法,父类则无法看到。
class-pattern
类名表达式匹配
method-pattern
方法名表达式匹配
-d
展示每个方法的详细信息
-E
开启正则表达式匹配,默认为通配符匹配
jad
jad 包名+类名,反编译
参数
class-pattern
类名表达式匹配
-E
开启正则表达式匹配,默认为通配符匹配
–source-only
只显示源码,不显示类加载器,路径
也可以反编译指定的函数
jad demo.MathGame main
mc
在内存中把源代码编译成字节码文件
Memory Compiler/内存编译器,编译.java文件生成.class
编译,默认在arthas安装目录下
mc /Test.java
可以通过-d命令指定输出目录
mc /Test.java -d /指定目录
redefine
把新生成的字节码文件在内存中执行
加载外部的.class文件,redefine到JVM里
注意, redefine后的原来的类不能恢复,redefine有可能失败(比如增加了新的field) 。
reset命令对redefine的类无效。如果想重置,需要redefine原始的字节码。
redefine命令和jad /watch /trace/monitor /tt等命令会冲突。执行完redefine之后,如果再执行上面提到的命令,则会把redefine的字节码重置。
限制
-
不允许新增加field / method
-
正在跑的函数,没有退出不能生效,比如正在运行的循环内代码,但循环内调用的函数,是可以修改的,因为函数调用一次就结束了
classloader
获取类加载器的信息
classloader命令将JVM中所有的classloader的信息统计出来,并可以展示继承树,urls等。
可以让指定的classloader去getResources,打印出所有查找到的resources的url。对于ResourceNotFoundException异常比较有用。
monitor
monitor命令:监控指定类中方法的执行情况
对匹配class-pattern / method-pattern的类、方法的调用进行监控。
class-pattern
类名表达式匹配
method-pattern
方法名表达式匹配
-E
开启正则表达式匹配,默认为通配符匹配
-c
统计周期,默认值为120秒,单位秒
列名 | 说明 |
---|---|
timestamp | 返回时间 |
class | 类名 |
method | 方法名 |
total | 调用次数 |
success | 执行成功次数 |
fail | 抛出异常次数(失败次数) |
avg-rt(ms) | 平均执行时间 |
fail-rate | 失败率 |
watch 监视
观察到指定方法的调用情况
方法执行数据观测,让你能方便的观察到指定方法的调用情况。
能观察到的范围为:返回值、抛出异常、入参,通过编写OGNL表达式进行对应变量的查看。
参数
class-pattern
类名表达式匹配
method-pattern
方法名表达式匹配
express
观察表达式:OGNL
观察表达式的构成主要由ognl表达式组成,
{params,return0bj},
只要是一个合法的ognl表达式,都能被正常支持。
condition-express
条件表达式
-b
在方法调用之前观察before
-e
在方法异常之后观察exception
-s
在方法返回之后观察
-f
在方法结束之后(正常返回和异常返回)观察finally
-E
开启正则表达式匹配,默认为通配符匹配
-x
指定输出结果的属性遍历深度,默认为1
-
watch 命令定义了4个观察事件点,即 -b方法调用前,-e方法异常后,-s方法返回后,-f 方法结束后。
-
4个观察事件点-b、-e、-s 默认关闭,-f默认打开,当指定观察点被打开后,在相应事件点会对观察表达式进行求值并输出
-
这里要注意方法入参和方法出参的区别,有可能在中间被修改导致前后不一致,除了-b事件点params代表方法入参外,其余事件都代表方法出参
-
当使用-b时,由于观察事件点是在方法调用前,此时返回值或异常均不存在
watch demo.MathGame primeFactors returnObj
过滤不关心的调用 condition-express
只查看 参数1 为 Hello 的
watch StringUtils contains returnObj 'params[1]=="Hello"'
trace
对方法内部调用路径进行追踪,并输出方法路径上的每个节点上耗时
class-pattern
类名表达匹配
method-pattern
方法名表达式匹配
condition-express
条件表达式,使用OGNL表达式
-E
开启正则表达式匹配,默认是通配符匹配
-n
设置命令执行次数
#cost
方法执行耗时,单位是毫秒
例子
- trace函数指定类的指定方法
trace demo.MathGame run
2.默认情况下,trace不会包含jdk里的函数调用,如果希望trace jdk里的函数,需要显式设置–skipJDKMethod false。
trace --skipJDKMethod false demo.MathGame run
3.根据调用耗时过滤,trace大于0.5ms的调用路径
trace demo.MathGame run '#cost > .5'
stack
输出当前方法被调用的调用路径
很多时候我们都知道一个方法被执行,但这个方法被执行的路径非常多,或者你根本就不知道这个方法是从那里被执行了,此时你需要的是stack命令。
class-pattern
类名表达式匹配
method-pattern
方法名表达式匹配
condition-express
条件表达式,OGNL
-E
开启正则表达式匹配,默认为通配符匹配
-n
执行次数限制
获取primeFactors的调用路径
stack demo.MathGame primeFactors
条件表达式来过滤,第8个参数的值小于0
stack demo.MathGame primeFactors 'params[0]<0'
据执行时间来过滤,耗时大于0.5毫秒
stack demo.MathGame primeFactors '#cost>0.5'
tt
time-tunnel时间隧道
记录下指定方法每次调用的入参和返回信息,并能对这些不同时间下调用的信息进行观测
-t
记录某个方法在一个时间段中的调用
-l
显示所有已经记录的列表
-n
只记录多少次
-s
搜索表达式
-i
查看指定索引号的详细调用信息
-p
重新调用指定的索引号时间碎片
解决方法重载
tt -t *Test print params. length==1
通过制定参数个数的形式解决不同的方法签名,如果参数个数一样,还可以这样写
tt -t *Test print 'params[1] instanceof Integer'
解决指定参数
tt -t *Test print params[0].name=="xxxx"
重新调用指定次数,并查看详细信息
tt -i {id} -p --replay-times 3
profiler 火焰图
profiler 命令支持生成应用热点的火焰图。本质上是通过不断的采样,然后把收集到的采样结果生成火焰图。
命令基本运行结构是profiler命令[命令参数]
开始采样
profiler start
查看采样列表
profiler list
查看已采集到的样本数量
profiler getSamples
查看采集了多久
profiler status
结束采样,生成svg火焰图
profiler stop
profiler stop --format html
火焰图是基于perf结果产生的SVG图片,用来展示CPU的调用栈。颜色没有含义。
y轴表示调用栈,每一层都是一个函数。调用栈越深,火焰就越高,顶部就是正在执行的函数,下方都是它的父函数。
×轴表示抽样数,如果一个函数在×轴占据的宽度越宽,就表示它被抽到的次数多,即执行的时间长。注意,x轴不代表时间,而是所有的调用栈合并后,按字母顺序排列的。
火焰图就是看顶层的哪个函数占据的宽度最大。只要有“平顶"(plateaus),就表示该函数可能存在性能问题。
reset
还原增强类
还原指定类
reset Test
还原所有以List结尾的类
reset *List
还原所有的类(啥参数也不带)
reset
help
查看命令帮助信息
cls
清屏
退出
退出当前连接: quit 或 exit
完全退出:stop
jad + mc + redefine热更新
-
使用jad反编译demo.MathGame输出到/root/MathGame.java
jad --source-only demo.MathGame >/root/MathGame.java -
按上面的代码编辑完毕以后,使用mc内存中对新的代码编译
mc /root/MathGame.java -d /root -
使用redefine命令加载新的字节码
redefine /root/demo/MathGame.class