Arthas学习笔记

安装与启动

可以直接下载编译后的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可以自动补全命令

  1. 第一部分是显示JVM中运行的所有线程:所在线程组,优先级,线程的状态,CPU的占用率,是否是后台进程等

  2. 第二部分显示的JVM内存的使用情况

  3. 第三部分是操作系统的一些信息和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
方法执行耗时,单位是毫秒

例子

  1. 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热更新

  1. 使用jad反编译demo.MathGame输出到/root/MathGame.java
    jad --source-only demo.MathGame >/root/MathGame.java

  2. 按上面的代码编辑完毕以后,使用mc内存中对新的代码编译
    mc /root/MathGame.java -d /root

  3. 使用redefine命令加载新的字节码
    redefine /root/demo/MathGame.class

你可能感兴趣的:(jvm,java)