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

classloader

classloader 命令将 JVM 中所有的 classloader 的信息统计出来,并可以展示继承树,urls

# 按类型查看信息
classloader

# 查看继承树
classloader -t

# 查看加载的包
classloader -c [hash]

搜索类 - sc

sc demo.*
 
#[d]	输出当前类的详细信息,包括这个类所加载的原始文件来源、类的声明、加载的ClassLoader等详细信息。 如果一个类被多个ClassLoader所加载,则会出现多次
sc -d demo.MathGame
 
# 输出当前类的成员变量信息(需要配合参数-d一起使用)
sc -d -f demo.MathGame

搜索方法 - sm

sm demo.MathGame
 
# 展示每个方法的详细信息
sm -d demo.MathGame

反编译 - jad

jad java.lang.String
 
# 反编译结果里会带有ClassLoader信息,通过--source-only选项,可以只打印源代码
jad --source-only demo.MathGame
 
# 指定某一个方法+ 不显示行号
jad --source-only  com.fr.decision.authority.controller.SoftDataControllerImpl findById --lineNumber false
 
# 反编译时指定ClassLoader
jad org.apache.log4j.Logger -c 69dcaba4

编译 - mc

mc /home/ligen/Test.java
 
# -d命令指定输出目录
mc /home/ligen/Test.java -d /home/ligen

重新加载 - redefine

  • 不允许新增加field/method,只能基于已有的方法和成员变量
  • 正在跑的函数,没有退出不能生效,比如下面新增加的System.out.println,只有main()函数里的不会生效
jad --source-only demo.MathGame >> /home/ligen/MathGame.java
# 修改java文件
mc /home/ligen/MathGame.java -d /home/ligen/
redefine /home/ligen/demo/MathGame.class

thread

查看当前线程信息,查看线程的堆栈

这里的 cpu 使用率与 linux 命令top -H -p <pid> 的线程%CPU类似,一段采样间隔时间内,当前 JVM 里各个线程的增量 cpu 时间与采样间隔时间的比例。

thread --all > /Users/anner/Downloads/1.txt
# 查看指定状态 , 耗时前三个的线程
thread --state TIMED_WAITING -n 3

# 查找最耗时的线程 block
thread -b

# 指定采样时间
thread -n 3 -i 1000

trace

trace org.apache.commons.lang.StringUtils isBlank
trace *StringUtils isBlank
trace *StringUtils isBlank params[0].length==1
trace *StringUtils isBlank '#cost>100'
trace -E org\\\\.apache\\\\.commons\\\\.lang\\\\.StringUtils isBlank
trace -E com.test.ClassA|org.test.ClassB method1|method2|method3
trace demo.MathGame run -n 5
trace demo.MathGame run --skipJDKMethod false
trace javax.servlet.Filter * --exclude-class-pattern com.demo.TestFilter
trace OuterClass$InnerClass *

watch 查看参数

-b 函数调用前

-s 函数返回后

-e 函数异常

-f 函数正常结束或者异常结束

-x 参数的查看堆栈 ,一个bean 可能需要多个层数查看

watch com.fr.decision.webservice.v10.login.LoginService login "{params,target,returnObj,throwExp}"

# 比较常用的场景
watch  com.fr.decision.webservice.v10.entry.ReportEntryService getReportTemplateTree "{params[0],returnObj}"

watch -b com.fr.decision.webservice.v10.entry.ReportEntryService getReportTemplateTree params -x 2

watch -f com.fr.decision.webservice.v10.entry.ReportEntryService getReportTemplateTree returnObj

stack

输出当前方法被调用的调用路径

stack org.apache.commons.lang.StringUtils isBlank

stack *StringUtils isBlank
stack *StringUtils isBlank params[0].length==1
stack *StringUtils isBlank '#cost>100'
stack -E org\\.apache\\.commons\\.lang\\.StringUtils isBlank

profiler 火焰图

profiler 命令支持生成应用热点的火焰图。本质上是通过不断的采样,然后把收集到的采样结果生成火焰图

y 轴表示调用栈,每一层都是一个函数。调用栈越深,火焰就越高,顶部就是正在执行的函数,下方都是它的父函数。

x 轴表示抽样数,如果一个函数在 x 轴占据的宽度越宽,就表示它被抽到的次数多,即执行的时间长。注意,x 轴不代表时间,而是所有的调用栈合并后,按字母顺序排列的。

火焰图就是看顶层的哪个函数占据的宽度最大。只要有”平顶”(plateaus),就表示该函数可能存在性能问题。

颜色没有特殊含义,因为火焰图表示的是 CPU 的繁忙程度,所以一般选择暖色调。

profiler 区分不同的event 默认是采集cpu

在不同的平台,不同的 OS 下面,支持的 events 各有不同。比如在 macos 下面:

profiler list

Basic events:
  cpu
  alloc
  lock
  wall
  itimer
Java method calls:
  ClassName.methodName
profiler start

# 指定运行的时间
profiler start --duration 300
# jfr 只支持在 start时配置。如果是在stop时指定不生效
profiler start --file /tmp/test.jfr


profiler status

# 获取已采集的 sample 的数量
profiler getSamples

# start是新开始采样,resume会保留上次`stop`时的数据。
profiler resume

profiler stop --format html

file参数支持一些变量:

  • 时间戳: —file /tmp/test-%t.jfr
  • 进程 ID: —file /tmp/test-%p.jfr

生成的结果可以用支持 jfr 格式的工具来查看。比如: