Windows下Arthas的安装和卸载
万字长文!你还敢说你看不懂阿里开源Java神器Arthas?
Arthas描述
Arthas 是Alibaba开源的Java诊断工具,深受开发者喜爱。
当你遇到以下类似问题而束手无策时,Arthas可以帮助你解决:
1、这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?
2、我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?
3、遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?
4、线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!
5、是否有一个全局视角来查看系统的运行状况?
6、有什么办法可以监控到JVM的实时运行状态?
7、怎么快速定位应用的热点,生成火焰图?
监控方法命令
请注意,这些命令,都通过字节码增强技术来实现的,会在指定类的方法中插入一些切面来实现数据统计和观测,
因此在线上、预发使用时,请尽量明确需要观测的类、方法以及条件,诊断结束要执行 stop 或将增强过的类执行 reset 命令。
1、quit 退出当前 Arthas 客户端,其他 Arthas 客户端不受影响
2、shutdown——关闭 Arthas 服务端,所有 Arthas 客户端全部退出
3、stop——和shutdown命令一致
monitor——方法执行监控
watch——方法执行数据观测
trace——方法内部调用路径,并输出方法路径上的每个节点上耗时
stack——输出当前方法被调用的调用路径
tt——方法执行数据的时空隧道,记录下指定方法每次调用的入参和返回信息,并能对这些不同的时间下调用进行观测
watch
让你能方便的观察到指定方法的调用情况。
能观察到的范围为:返回值、抛出异常、入参,通过编写 OGNL 表达式进行对应变量的查看。
参数说明:
class-pattern 类名表达式匹配
method-pattern 方法名表达式匹配
express 观察表达式
condition-express 条件表达式
-b 在方法调用之前观察
-e 在方法异常之后观察
-s 在方法返回之后观察
-f 在方法结束之后(正常返回和异常返回)观察 默认开启
-E 开启正则表达式匹配,默认为通配符匹配
-x 指定输出结果的属性遍历深度,默认为 1
-n 执行的次数
特别说明:
watch 命令定义了4个观察事件点,
即 -b 方法调用前,-e 方法异常后,-s 方法返回后,-f 方法结束后
4个观察事件点 -b、-e、-s 默认关闭,-f 默认打开,
当指定观察点被打开后,在相应事件点会对观察表达式进行求值并输出
这里要注意方法入参和方法出参的区别,有可能在中间被修改导致前后不一致,
除了 -b 事件点 params 代表方法入参外,其余事件都代表方法出参
当使用 -b 时,由于观察事件点是在方法调用前,此时返回值或异常均不存在
-x 代表输出结果的深度 ,默认为 1
使用参考:
常规用法:
watch class method {params,returnObj,throwExp} -x 1 '#cost>200'
观察表达式 { } 可以包裹结果集 , 分割。输出的表达式变量定义
params 代表参数数组,returnObj 代表返回值,throwExp 代表抛出的异常。
过滤耗时大于200ms的
特殊用法:
1、调用第一个参数的方法或属性
watch class method "{params[0].length()}" -x 1
如果是列表参数,则可以使用这种方式来获取列表中每个对象的指定属性
watch class method "{params[0].{ #this.length()}}" -x 1
2、按照条件过滤
如果是列表,则会过滤列表中长度大于7的字符串
watch class method "{params[0].{? #this.length() > 7}}" -x 1
watch class method "{params,returnObj,throwExp}" "params[0].length() > 7" -x 1
字符串长度 > 7 才会输出 params[0] 的值
3、过滤后统计
watch class method "{params[0].{? #this.length() > 9}.size()}" -x 1
4、过滤列表参数格式
获取列表中每个对象的name属性
watch class method "{params[0].{name}}" -n 1 -x 1
watch class method "{params[0].users.{name}}" -n 1 -x 1
也可以使用方法获取
watch class method "{params[0].{getName()}}" -n 1 -x 1
也可以使用条件进行过滤筛选
watch class method "{params[0].{? name.length() > 5}}" -n 1 -x 1
按条件过滤后展示指定属性
watch class method "{params[0].{? #this.name.length() > 5}.{age}}" -n 1 -x 1
找到第一个符合条件的数据,用^
watch class method "{params[0].{^ #this.name.length() > 5}.{age}}" -n 1 -x 1
找到最后一个符合条件的数据,用$
watch class method "{params[0].{$ #this.name.length() > 5}.{age}}" -n 1 -x 1
使用临时变量,然后进行相关操作,然后展示
watch class method "(#test=params[0].{? #this.name.length() > 5}.{name}, #test.add('zhangsan'), #test)" -n 1 -x 1
获取列表中每个对象的id,name属性,并用逗号衔接,然后一行输出
watch class method "{params[0].users.{id + ',' + name}}" -n 1 -x 1
trace
trace 命令能主动搜索 class-pattern/method-pattern 对应的方法内部调用路径,
渲染和统计整个调用链路上的所有性能开销和追踪调用链路。
参数说明:
class-pattern 类名表达式匹配
method-pattern 方法名表达式匹配
condition-express 条件表达式
-E 开启正则表达式匹配,默认为通配符匹配,可以加上该参数,然后根据参数或者返回值进行条件过滤
-n 命令执行次数
#cost 方法执行耗时
使用参考:
常规用法:
trace class method '#cost>100' -n 1
过滤大于100ms的调用链,只输出一次
特殊用法:
trace命令只会trace匹配到的函数里的子调用,并不会向下trace多层。
因为trace是代价比较贵的,多层trace可能会导致最终要trace的类和函数非常多。
动态trace:
3.3.0 版本后支持。
打开终端1,trace run函数,可以看到打印出 listenerId: 1:
[arthas@59161]$ trace demo.MathGame run
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 112 ms, listenerId: 1
`---ts=2020-07-09 16:48:11;thread_name=main;id=1;is_daemon=false;priority=5;TCCL=sun.misc.Launcher$AppClassLoader@3d4eac69
`---[1.389634ms] demo.MathGame:run()
`---[0.123934ms] demo.MathGame:primeFactors() #24 [throws Exception]
现在想要深入子函数primeFactors,可以打开一个新终端2,
使用telnet localhost 3658连接上arthas,
再trace primeFactors时,指定listenerId。
再查看终端1,可以发现trace的结果增加了一层,打印了primeFactors函数里的内容
`---ts=2020-07-09 16:49:29;thread_name=main;id=1;is_daemon=false;priority=5;TCCL=sun.misc.Launcher$AppClassLoader@3d4eac69
`---[0.492551ms] demo.MathGame:run()
`---[0.113929ms] demo.MathGame:primeFactors() #24 [throws Exception]
`---[0.061462ms] demo.MathGame:primeFactors()
`---[0.001018ms] throw:java.lang.IllegalArgumentException() #46
通过指定listenerId的方式动态trace,可以不断深入。
另外 watch/tt/monitor等命令也支持类似的功能。
tt
方法执行数据的时空隧道,记录下指定方法每次调用的入参和返回信息,并能对这些不同的时间下调用进行观测。
watch 虽然很方便和灵活,但需要提前想清楚观察表达式的拼写,这对排查问题而言要求太高。
因为很多时候我们并不清楚问题出自于何方,只能靠蛛丝马迹进行猜测。
这个时候如果能记录下当时方法调用的所有入参和返回值、抛出的异常会对整个问题的思考与判断非常有帮助。
于是乎,TimeTunnel 命令就诞生了。
参数说明:
-n 执行次数
#cost 过滤耗时
-t tt 命令有很多个主参数,-t 就是其中之一。
这个参数的表明希望记录下类 *Test 的 print 方法的每次执行情况。
-s 可以跟条件表达式 进行筛选
-l 列出所有的记录
-i INDEX编号 查看对应的INDEX编号的详细信息
记录说明:
表格字段 字段解释
INDEX 时间片段记录编号,每一个编号代表着一次调用,后续tt还有很多命令都是基于此编号指定记录操作,非常重要。
TIMESTAMP 方法执行的本机时间,记录了这个时间片段所发生的本机时间COST(ms) 方法执行的耗时
IS-RET 方法是否以正常返回的形式结束
IS-EXP 方法是否以抛异常的形式结束
OBJECT 执行对象的hashCode(),注意,曾经有人误认为是对象在JVM中的内存地址,但很遗憾他不是。但他能帮助你简单的标记当前执行方法的类实体
CLASS 执行的类名METHOD执行的方法名
使用参考:
tt -t class method '#cost>100'
INDEX TIMESTAMP COST(ms) IS-RET IS-EXP OBJECT CLASS METHOD
-------------------------------------------------------------------------------------------------------------------------------------
1000 2018-12-04 11:15:38 1.096236 false true 0x4b67cf4d MathGame primeFactors
1001 2018-12-04 11:15:39 0.191848 false true 0x4b67cf4d MathGame primeFactors
1002 2018-12-04 11:15:40 0.069523 false true 0x4b67cf4d MathGame primeFactors
1003 2018-12-04 11:15:41 0.186073 false true 0x4b67cf4d MathGame primeFactors
1004 2018-12-04 11:15:42 17.76437 true false 0x4b67cf4d MathGame
查看调用信息:
对于具体一个时间片的信息而言,你可以通过 -i 参数后边跟着对应的 INDEX 编号查看到他的详细信息。
tt -i 1003
$ tt -i 1003
INDEX 1003
GMT-CREATE 2018-12-04 11:15:41
COST(ms) 0.186073
OBJECT 0x4b67cf4d
CLASS demo.MathGame
METHOD primeFactors
IS-RETURN false
IS-EXCEPTION true
PARAMETERS[0] @Integer[-564322413]
THROW-EXCEPTION java.lang.IllegalArgumentException: number is: -564322413, need >= 2
at demo.MathGame.primeFactors(MathGame.java:46)
at demo.MathGame.run(MathGame.java:24)
at demo.MathGame.main(MathGame.java:16)
Affect(row-cnt:1) cost in 11 ms.
tt -l 查看我们现有的记录
$ tt -l
INDEX TIMESTAMP COST(ms) IS-RET IS-EXP OBJECT CLASS METHOD
-------------------------------------------------------------------------------------------------------------------------------------
1000 2018-12-04 11:15:38 1.096236 false true 0x4b67cf4d MathGame primeFactors
1001 2018-12-04 11:15:39 0.191848 false true 0x4b67cf4d MathGame primeFactors
1002 2018-12-04 11:15:40 0.069523 false true 0x4b67cf4d MathGame primeFactors
1003 2018-12-04 11:15:41 0.186073 false true 0x4b67cf4d MathGame primeFactors
1004 2018-12-04 11:15:42 17.76437 true false 0x4b67cf4d MathGame primeFactors
9
1005 2018-12-04 11:15:43 0.4776 false true 0x4b67cf4d MathGame primeFactors
Affect(row-cnt:6) cost in 4 ms.
我需要筛选出 primeFactors 方法的调用信息
tt -s
$ tt -s 'method.name=="primeFactors"'
INDEX TIMESTAMP COST(ms) IS-RET IS-EXP OBJECT CLASS METHOD
-------------------------------------------------------------------------------------------------------------------------------------
1000 2018-12-04 11:15:38 1.096236 false true 0x4b67cf4d MathGame primeFactors
1001 2018-12-04 11:15:39 0.191848 false true 0x4b67cf4d MathGame primeFactors
1002 2018-12-04 11:15:40 0.069523 false true 0x4b67cf4d MathGame primeFactors
1003 2018-12-04 11:15:41 0.186073 false true 0x4b67cf4d MathGame primeFactors
1004 2018-12-04 11:15:42 17.76437 true false 0x4b67cf4d MathGame primeFactors
9
1005 2018-12-04 11:15:43 0.4776 false true 0x4b67cf4d MathGame primeFactors
Affect(row-cnt:6) cost in 607 ms.
stack
很多时候我们都知道一个方法被执行,但这个方法被执行的路径非常多,
或者你根本就不知道这个方法是从那里被执行了,此时你需要的是 stack 命令。
参数说明:
class-pattern 类名表达式匹配
method-pattern 方法名表达式匹配
condition-express 条件表达式
-E 开启正则表达式匹配,默认为通配符匹配
-n 执行次数限制
使用参考:
stack class method ’#cost>5‘
stack demo.MathGame primeFactors ’#cost>5‘
输出调用链,按照执行时间过滤
stack demo.MathGame primeFactors 'params[0]<0' -n 2
按照条件表达式进行过滤
monitor
参数说明:
class-pattern 类名表达式匹配
method-pattern 方法名表达式匹配
condition-express 条件表达式
-E 开启正则表达式匹配,默认为通配符匹配
-c 统计周期,默认值为120秒
方法拥有一个命名参数 [c:],意思是统计周期(cycle of output),拥有一个整型的参数值
-b 在方法调用之前计算condition-express
监控的维度说明:
监控项 说明
timestamp 时间戳
class Java类
method 方法(构造方法、普通方法)
total 调用次数
success 成功次数
fail 失败次数
rt 平均RT
fail-rate 失败率
使用参考:
monitor -c 5 class method
monitor -c 5 demo.MathGame primeFactors
每5秒统计一次
$ monitor -c 5 demo.MathGame primeFactors
Press Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 94 ms.
timestamp class method total success fail avg-rt(ms) fail-rate
-----------------------------------------------------------------------------------------------
2018-12-03 19:06:38 demo.MathGame primeFactors 5 1 4 1.15 80.00%
timestamp class method total success fail avg-rt(ms) fail-rate
-----------------------------------------------------------------------------------------------
2018-12-03 19:06:43 demo.MathGame primeFactors 5 3 2 42.29 40.00%
timestamp class method total success fail avg-rt(ms) fail-rate
-----------------------------------------------------------------------------------------------
2018-12-03 19:06:48 demo.MathGame primeFactors 5 3 2 67.92 40.00%
timestamp class method total success fail avg-rt(ms) fail-rate
-----------------------------------------------------------------------------------------------
2018-12-03 19:06:53 demo.MathGame primeFactors 5 2 3 0.25 60.00%
timestamp class method total success fail avg-rt(ms) fail-rate
-----------------------------------------------------------------------------------------------
2018-12-03 19:06:58 demo.MathGame primeFactors 1 1 0 0.45 0.00%
timestamp class method total success fail avg-rt(ms) fail-rate
-----------------------------------------------------------------------------------------------
2018-12-03 19:07:03 demo.MathGame primeFactors 2 2 0 3182.72 0.00%
计算条件表达式过滤统计结果(方法执行完毕之后)
monitor -c 5 demo.MathGame primeFactors "params[0] <= 2"
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 19 ms, listenerId: 5
timestamp class method total success fail avg-rt(ms) fail-rate
-----------------------------------------------------------------------------------------------
2020-09-02 09:42:36 demo.MathGame primeFactors 5 3 2 0.09 40.00%
timestamp class method total success fail avg-rt(ms) fail-rate
----------------------------------------------------------------------------------------------
2020-09-02 09:42:41 demo.MathGame primeFactors 5 2 3 0.11 60.00%
timestamp class method total success fail avg-rt(ms) fail-rate
----------------------------------------------------------------------------------------------
2020-09-02 09:42:46 demo.MathGame primeFactors 5 1 4 0.06 80.00%
timestamp class method total success fail avg-rt(ms) fail-rate
----------------------------------------------------------------------------------------------
2020-09-02 09:42:51 demo.MathGame primeFactors 5 1 4 0.12 80.00%
timestamp class method total success fail avg-rt(ms) fail-rate
----------------------------------------------------------------------------------------------
2020-09-02 09:42:56 demo.MathGame primeFactors 5 3 2 0.15 40.00%
jvm相关
dashboard——当前系统的实时数据面板
thread——查看当前 JVM 的线程堆栈信息
jvm——查看当前 JVM 的信息
sysprop——查看和修改JVM的系统属性
sysenv——查看JVM的环境变量
vmoption——查看和修改JVM里诊断相关的option
perfcounter——查看当前 JVM 的Perf Counter信息
logger——查看和修改logger
getstatic——查看类的静态属性
ognl——执行ognl表达式
mbean——查看 Mbean 的信息
heapdump——dump java heap, 类似jmap命令的heap dump功能
dashboard
当前系统的实时数据面板,按 ctrl+c 退出。
使用参考:
dashboard -i 5000 -n 10
-i 刷新实时数据的时间间隔 (ms),默认5000ms
-n 刷新数据的次数
数据说明:
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线程
thread
查看当前线程信息,查看线程的堆栈
参数说明:
id 线程id
-n 指定最忙的前N个线程并打印堆栈
-b 找出当前阻塞其他线程的线程
-i 指定cpu使用率统计的采样间隔,单位为毫秒,默认值为200
--all 显示所有匹配的线程
--state 查看指定状态的线程
使用参考:
thread -b, 找出当前阻塞其他线程的线程
有时候我们发现应用卡住了, 通常是由于某个线程拿住了某个锁, 并且其他线程都在等待这把锁造成的。
为了排查这类问题, arthas提供了thread -b, 一键找出那个罪魁祸首
thread -i 1000 : 统计最近1000ms内的线程CPU时间。
thread -n 3 -i 1000 : 列出1000ms内最忙的3个线程栈
thread --state WAITING 列出等待态的线程
jvm
查看当前JVM信息
使用参考:
$ jvm
RUNTIME
--------------------------------------------------------------------------------------------------------------
MACHINE-NAME 37@ff267334bb65
JVM-START-TIME 2020-07-23 07:50:36
MANAGEMENT-SPEC-VERSION 1.2
SPEC-NAME Java Virtual Machine Specification
SPEC-VENDOR Oracle Corporation
SPEC-VERSION 1.8
VM-NAME Java HotSpot(TM) 64-Bit Server VM
VM-VENDOR Oracle Corporation
VM-VERSION 25.201-b09
INPUT-ARGUMENTS []
CLASS-PATH demo-arthas-spring-boot.jar
BOOT-CLASS-PATH /usr/lib/jvm/java-8-oracle/jre/lib/resources.jar:/usr/lib/jvm/java-8-oracle/j
re/lib/rt.jar:/usr/lib/jvm/java-8-oracle/jre/lib/sunrsasign.jar:/usr/lib/jvm/
java-8-oracle/jre/lib/jsse.jar:/usr/lib/jvm/java-8-oracle/jre/lib/jce.jar:/us
r/lib/jvm/java-8-oracle/jre/lib/charsets.jar:/usr/lib/jvm/java-8-oracle/jre/l
ib/jfr.jar:/usr/lib/jvm/java-8-oracle/jre/classes
LIBRARY-PATH /usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib
--------------------------------------------------------------------------------------------------------------
CLASS-LOADING
--------------------------------------------------------------------------------------------------------------
LOADED-CLASS-COUNT 7529
TOTAL-LOADED-CLASS-COUNT 7529
UNLOADED-CLASS-COUNT 0
IS-VERBOSE false
--------------------------------------------------------------------------------------------------------------
COMPILATION
--------------------------------------------------------------------------------------------------------------
NAME HotSpot 64-Bit Tiered Compilers
TOTAL-COMPILE-TIME 14921(ms)
--------------------------------------------------------------------------------------------------------------
GARBAGE-COLLECTORS
--------------------------------------------------------------------------------------------------------------
PS Scavenge name : PS Scavenge
[count/time (ms)] collectionCount : 7
collectionTime : 68
PS MarkSweep name : PS MarkSweep
[count/time (ms)] collectionCount : 1
collectionTime : 47
--------------------------------------------------------------------------------------------------------------
MEMORY-MANAGERS
--------------------------------------------------------------------------------------------------------------
CodeCacheManager Code Cache
Metaspace Manager Metaspace
Compressed Class Space
Copy Eden Space
Survivor Space
MarkSweepCompact Eden Space
Survivor Space
Tenured Gen
--------------------------------------------------------------------------------------------------------------
MEMORY
--------------------------------------------------------------------------------------------------------------
HEAP-MEMORY-USAGE init : 268435456(256.0 MiB)
[memory in bytes] used : 18039504(17.2 MiB)
committed : 181403648(173.0 MiB)
max : 3817865216(3.6 GiB)
NO-HEAP-MEMORY-USAGE init : 2555904(2.4 MiB)
[memory in bytes] used : 33926216(32.4 MiB)
committed : 35176448(33.5 MiB)
max : -1(-1 B)
--------------------------------------------------------------------------------------------------------------
OPERATING-SYSTEM
--------------------------------------------------------------------------------------------------------------
OS Linux
ARCH amd64
PROCESSORS-COUNT 3
LOAD-AVERAGE 29.53
VERSION 4.15.0-52-generic
--------------------------------------------------------------------------------------------------------------
THREAD
--------------------------------------------------------------------------------------------------------------
COUNT 30
DAEMON-COUNT 24
PEAK-COUNT 31
STARTED-COUNT 36
DEADLOCK-COUNT 0
--------------------------------------------------------------------------------------------------------------
FILE-DESCRIPTOR
--------------------------------------------------------------------------------------------------------------
MAX-FILE-DESCRIPTOR-COUNT 1048576
OPEN-FILE-DESCRIPTOR-COUNT 100
Affect(row-cnt:0) cost in 88 ms.
THREAD相关:
COUNT: JVM当前活跃的线程数
DAEMON-COUNT: JVM当前活跃的守护线程数
PEAK-COUNT: 从JVM启动开始曾经活着的最大线程数
STARTED-COUNT: 从JVM启动开始总共启动过的线程次数
DEADLOCK-COUNT: JVM当前死锁的线程数
文件描述符相关:
MAX-FILE-DESCRIPTOR-COUNT: JVM进程最大可以打开的文件描述符数
OPEN-FILE-DESCRIPTOR-COUNT: JVM当前打开的文件描述符数
heapdump
dump java heap, 类似jmap命令的heap dump功能。
使用参考:
dump到指定文件:
[arthas@58205]$ heapdump /tmp/dump.hprof
Dumping heap to /tmp/dump.hprof...
Heap dump file created
只dump live对象:
[arthas@58205]$ heapdump --live /tmp/dump.hprof
Dumping heap to /tmp/dump.hprof...
Heap dump file created
dump到临时文件:
[arthas@58205]$ heapdump
Dumping heap to /var/folders/my/wy7c9w9j5732xbkcyt1mb4g40000gp/T/heapdump2019-09-03-16-385121018449645518991.hprof...
Heap dump file created
sysprop 和 sysenv
sysprop 查看和修改当前JVM的系统属性(System Property)
sysenv 查看当前JVM的环境属性(System Environment Variables)
sysprop 和 sysenv使用方式类似
使用参考:
$ sysprop
KEY VALUE
-------------------------------------------------------------------------------------------------------------------------------------
java.runtime.name Java(TM) SE Runtime Environment
sun.boot.library.path /Library/Java/JavaVirtualMachines/jdk1.8.0_51.jdk/Contents/Home/jre/lib
java.vm.version 25.51-b03
user.country.format CN
gopherProxySet false
java.vm.vendor Oracle Corporation
java.vendor.url http://java.oracle.com/
path.separator :
java.vm.name Java HotSpot(TM) 64-Bit Server VM
file.encoding.pkg sun.io
user.country US
sun.java.launcher SUN_STANDARD
sun.os.patch.level unknown
java.vm.specification.name Java Virtual Machine Specification
user.dir /private/var/tmp
java.runtime.version 1.8.0_51-b16
java.awt.graphicsenv sun.awt.CGraphicsEnvironment
java.endorsed.dirs /Library/Java/JavaVirtualMachines/jdk1.8.0_51.jdk/Contents/Home/jre/lib/endors
ed
os.arch x86_64
java.io.tmpdir /var/folders/2c/tbxwzs4s4sbcvh7frbcc7n000000gn/T/
line.separator
java.vm.specification.vendor Oracle Corporation
os.name Mac OS X
sun.jnu.encoding UTF-8
java.library.path /Users/wangtao/Library/Java/Extensions:/Library/Java/Extensions:/Network/Libra
ry/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java:.
sun.nio.ch.bugLevel
java.specification.name Java Platform API Specification
java.class.version 52.0
sun.management.compiler HotSpot 64-Bit Tiered Compilers
os.version 10.12.6
user.home /Users/wangtao
user.timezone Asia/Shanghai
java.awt.printerjob sun.lwawt.macosx.CPrinterJob
file.encoding UTF-8
java.specification.version 1.8
user.name wangtao
java.class.path .
java.vm.specification.version 1.8
sun.arch.data.model 64
查看单个属性 支持通过TAB键自动补全:
$ sysprop java.version
java.version=1.8.0_51
修改单个属性:
$ sysprop user.country
user.country=US
$ sysprop user.country CN
Successfully changed the system property.
user.country=CN
logger
查看logger信息,更新logger level
使用参考:
查看所有logger信息:
[arthas@2062]$ logger
name ROOT
class ch.qos.logback.classic.Logger
classLoader sun.misc.Launcher$AppClassLoader@2a139a55
classLoaderHash 2a139a55
level INFO
effectiveLevel INFO
additivity true
codeSource file:/Users/hengyunabc/.m2/repository/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar
appenders name CONSOLE
class ch.qos.logback.core.ConsoleAppender
classLoader sun.misc.Launcher$AppClassLoader@2a139a55
classLoaderHash 2a139a55
target System.out
name APPLICATION
class ch.qos.logback.core.rolling.RollingFileAppender
classLoader sun.misc.Launcher$AppClassLoader@2a139a55
classLoaderHash 2a139a55
file app.log
name ASYNC
class ch.qos.logback.classic.AsyncAppender
classLoader sun.misc.Launcher$AppClassLoader@2a139a55
classLoaderHash 2a139a55
appenderRef [APPLICATION]
从appenders的信息里,可以看到:
CONSOLE logger的target是System.out
APPLICATION logger是RollingFileAppender,它的file是app.log
ASYNC 它的appenderRef是APPLICATION,即异步输出到文件里
查看指定的logger信息:
按名字查找:
[arthas@2062]$ logger -n org.springframework.web
name org.springframework.web
class ch.qos.logback.classic.Logger
classLoader sun.misc.Launcher$AppClassLoader@2a139a55
classLoaderHash 2a139a55
level null
effectiveLevel INFO
additivity true
codeSource file:/Users/hengyunabc/.m2/repository/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar
指定classloader查找:
注意hashcode是变化的,需要先查看当前的ClassLoader信息,提取对应ClassLoader的hashcode。
如果你使用-c,你需要手动输入hashcode:-c <hashcode>
[arthas@2062]$ logger -c 2a139a55
name ROOT
class ch.qos.logback.classic.Logger
classLoader sun.misc.Launcher$AppClassLoader@2a139a55
classLoaderHash 2a139a55
level DEBUG
effectiveLevel DEBUG
additivity true
codeSource file:/Users/hengyunabc/.m2/repository/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar
appenders name CONSOLE
class ch.qos.logback.core.ConsoleAppender
classLoader sun.misc.Launcher$AppClassLoader@2a139a55
classLoaderHash 2a139a55
target System.out
name APPLICATION
class ch.qos.logback.core.rolling.RollingFileAppender
classLoader sun.misc.Launcher$AppClassLoader@2a139a55
classLoaderHash 2a139a55
file app.log
name ASYNC
class ch.qos.logback.classic.AsyncAppender
classLoader sun.misc.Launcher$AppClassLoader@2a139a55
classLoaderHash 2a139a55
appenderRef [APPLICATION]
更新 logger level:
[arthas@2062]$ logger --name ROOT --level debug
update logger level success.
指定classloader更新 logger level:
默认情况下,logger命令会在SystemClassloader下执行,
如果应用是传统的war应用,或者spring boot fat jar启动的应用,那么需要指定classloader。
[arthas@2062]$ logger -c 2a139a55 --name ROOT --level debug
class/classloader相关
jad
反编译指定已加载类的源码
jad 命令将 JVM 中实际运行的 class 的 byte code 反编译成 java 代码,便于你理解业务逻辑;
在 Arthas Console 上,反编译出来的源码是带语法高亮的,阅读更方便
当然,反编译出来的 java 代码可能会存在语法错误,但不影响你进行阅读理解
使用参考:
编译java.lang.String:
$ jad java.lang.String
ClassLoader:
Location:
/*
* Decompiled with CFR 0_132.
*/
package java.lang;
import java.io.ObjectStreamField;
...
public final class String
implements Serializable,
Comparable<String>,
CharSequence {
private final char[] value;
private int hash;
private static final long serialVersionUID = -6849794470754667710L;
private static final ObjectStreamField[] serialPersistentFields = new ObjectStreamField[0];
public static final Comparator<String> CASE_INSENSITIVE_ORDER = new CaseInsensitiveComparator();
public String(byte[] arrby, int n, int n2) {
String.checkBounds(arrby, n, n2);
this.value = StringCoding.decode(arrby, n, n2);
}
...
反编译时只显示源代码:
默认情况下,反编译结果里会带有ClassLoader信息,
通过--source-only选项,可以只打印源代码。
方便和mc/redefine命令结合使用。
$ jad --source-only demo.MathGame
/*
* Decompiled with CFR 0_132.
*/
package demo;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;
public class MathGame {
private static Random random = new Random();
public int illegalArgumentCount = 0;
...
反编译指定的函数:
jad demo.MathGame main
后台执行
arthas中的后台异步任务,使用了仿linux系统任务相关的命令。
1、使用&在后台执行任务
比如希望执行后台执行trace命令,那么调用下面命令
trace Test t &
这时命令在后台执行,可以在console中继续执行其他命令。
2、通过jobs查看任务
如果希望查看当前有哪些arthas任务在执行,可以执行jobs命令,执行结果如下
kill job-id 可以杀死指定任务
$ jobs
[10]*
Stopped watch com.taobao.container.Test test "params[0].{? #this.name == null }" -x 2
execution count : 19
start time : Fri Sep 22 09:59:55 CST 2017
timeout date : Sat Sep 23 09:59:55 CST 2017
session : 3648e874-5e69-473f-9eed-7f89660b079b (current)
可以看到目前有一个后台任务在执行。
job id是10, * 表示此job是当前session创建
状态是Stopped
execution count是执行次数,从启动开始已经执行了19次
timeout date是超时的时间,到这个时间,任务将会自动超时退出
任务转换:
fg <job-id> 可以把对应的任务转到前台继续执行
bg <job-id> 可以把对应的任务在后台继续执行
任务输出重定向:
可通过 > 或者 >> 将任务输出结果输出到指定的文件中,
可以和 & 一起使用,实现arthas命令的后台异步任务
$ trace Test t >> test.out &
其他
sc
sc命令官方文档
查看JVM已加载的类信息
参数说明:
class-pattern 类名表达式匹配
method-pattern 方法名表达式匹配
[d] 输出当前类的详细信息,
包括这个类所加载的原始文件来源、类的声明、加载的ClassLoader等详细信息。
如果一个类被多个ClassLoader所加载,则会出现多次
[E] 开启正则表达式匹配,默认为通配符匹配
[f] 输出当前类的成员变量信息(需要配合参数-d一起使用)
[x:] 指定输出静态变量时属性的遍历深度,默认为 0,即直接使用 toString 输出
[c:] 指定class的 ClassLoader 的 hashcode
[classLoaderClass:] 指定执行表达式的 ClassLoader 的 class name
[n:] 具有详细信息的匹配类的最大数量(默认为100)
特殊说明:
class-pattern支持全限定名,
如com.taobao.test.AAA,也支持com/taobao/test/AAA这样的格式,
这样,我们从异常堆栈里面把类名拷贝过来的时候,不需要在手动把/替换为.啦。
sc 默认开启了子类匹配功能,也就是说所有当前类的子类也会被搜索出来,
想要精确的匹配,请打开options disable-sub-class true开关
使用参考:
模糊搜索:
$ sc demo.*
demo.MathGame
Affect(row-cnt:1) cost in 55 ms.
打印类的详细信息:
$ sc -d demo.MathGame
class-info demo.MathGame
code-source /private/tmp/math-game.jar
name demo.MathGame
isInterface false
isAnnotation false
isEnum false
isAnonymousClass false
isArray false
isLocalClass false
isMemberClass false
isPrimitive false
isSynthetic false
simple-name MathGame
modifier public
annotation
interfaces
super-class +-java.lang.Object
class-loader +-sun.misc.Launcher$AppClassLoader@3d4eac69
+-sun.misc.Launcher$ExtClassLoader@66350f69
classLoaderHash 3d4eac69
Affect(row-cnt:1) cost in 875 ms.
打印出类的Field信息:
$ sc -d -f demo.MathGame
class-info demo.MathGame
code-source /private/tmp/math-game.jar
name demo.MathGame
isInterface false
isAnnotation false
isEnum false
isAnonymousClass false
isArray false
isLocalClass false
isMemberClass false
isPrimitive false
isSynthetic false
simple-name MathGame
modifier public
annotation
interfaces
super-class +-java.lang.Object
class-loader +-sun.misc.Launcher$AppClassLoader@3d4eac69
+-sun.misc.Launcher$ExtClassLoader@66350f69
classLoaderHash 3d4eac69
fields modifierprivate,static
type java.util.Random
name random
value java.util.Random@522b4
08a
modifierprivate
type int
name illegalArgumentCount
Affect(row-cnt:1) cost in 19 ms.
sm
sc命令官方文档
查看已加载类的方法信息
“Search-Method” 的简写,这个命令能搜索出所有已经加载了 Class 信息的方法信息。
sm 命令只能看到由当前类所声明 (declaring) 的方法,父类则无法看到。
参数说明:
class-pattern 类名表达式匹配
method-pattern 方法名表达式匹配
[d] 展示每个方法的详细信息
[E] 开启正则表达式匹配,默认为通配符匹配
[c:] 指定class的 ClassLoader 的 hashcode
[classLoaderClass:] 指定执行表达式的 ClassLoader 的 class name
[n:] 具有详细信息的匹配类的最大数量(默认为100)
使用参考:
$ sm java.lang.String
java.lang.String-><init>
java.lang.String->equals
java.lang.String->toString
java.lang.String->hashCode
java.lang.String->compareTo
java.lang.String->indexOf
java.lang.String->valueOf
java.lang.String->checkBounds
java.lang.String->length
java.lang.String->isEmpty
java.lang.String->charAt
java.lang.String->codePointAt
java.lang.String->codePointBefore
java.lang.String->codePointCount
java.lang.String->offsetByCodePoints
java.lang.String->getChars
java.lang.String->getBytes
java.lang.String->contentEquals
java.lang.String->nonSyncContentEquals
java.lang.String->equalsIgnoreCase
java.lang.String->compareToIgnoreCase
java.lang.String->regionMatches
java.lang.String->startsWith
java.lang.String->endsWith
java.lang.String->indexOfSupplementary
java.lang.String->lastIndexOf
java.lang.String->lastIndexOfSupplementary
java.lang.String->substring
java.lang.String->subSequence
java.lang.String->concat
java.lang.String->replace
java.lang.String->matches
java.lang.String->contains
java.lang.String->replaceFirst
java.lang.String->replaceAll
java.lang.String->split
java.lang.String->join
java.lang.String->toLowerCase
java.lang.String->toUpperCase
java.lang.String->trim
java.lang.String->toCharArray
java.lang.String->format
java.lang.String->copyValueOf
java.lang.String->intern
Affect(row-cnt:44) cost in 1342 ms.
$ sm -d java.lang.String toString
declaring-class java.lang.String
method-name toString
modifier public
annotation
parameters
return java.lang.String
exceptions
Affect(row-cnt:1) cost in 3 ms.
火焰图 profiler
profiler官方文档
profiler 命令支持生成应用热点的火焰图。本质上是通过不断的采样,然后把收集到的采样结果生成火焰图。
使用逻辑为,采样开始--执行被测试动作--采样结束--分析。
profiler 命令基本运行结构是 profiler action [actionArg]
参数说明:
action 要执行的操作
actionArg 属性名模式
[i:] 采样间隔(单位:ns)(默认值:10'000'000,即10 ms)
[f:] 将输出转储到指定路径
[d:] 运行评测指定秒
[e:] 要跟踪哪个事件(cpu, alloc, lock, cache-misses等),默认是cpu
1、启动profiler
默认情况下,生成的是cpu的火焰图,即event为cpu。可以用-e/--event参数来指定。
$ profiler start
Started [cpu] profiling
也可以指定执行时间,比如,希望profiler执行 300 秒自动结束,可以用 -d/--duration 参数指定:
profiler start --duration 300
2、获取已采集的sample的数量
$ profiler getSamples
23
3、查看profiler状态
可以查看当前profiler在采样哪种event和采样时间。
$ profiler status
[cpu] profiling is running for 4 seconds
4、生成svg格式结果
默认情况下,生成的结果保存到应用的工作目录下的arthas-output目录里。
$ profiler stop
profiler output file: /tmp/demo/arthas-output/20191125-135546.svg
OK
也可以用--format参数指定:
$ profiler stop --format html
profiler output file: /tmp/test/arthas-output/20211207-111550.html
OK
或者在--file参数里用文件名指名格式。比如-f/--file /tmp/result.html。
简化命令:
profiler start -d 30 -e cpu -f /tmp/profiler.svg