arthas 有什么用?
Arthas 是Alibaba开源的Java诊断工具,深受开发者喜爱。
以下是官方文档提到的 arthas 的作用。
当你遇到以下类似问题而束手无策时, Arthas 可以帮助你解决。
-
这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?
-
我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?
-
遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?
-
线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!
-
是否有一个全局视角来查看系统的运行状况?
-
有什么办法可以监控到JVM的实时运行状态?
-
怎么快速定位应用的热点,生成火焰图?
-
Arthas 支持JDK 6+,支持Linux/Mac/Winodws,采用命令行交互模式,同时提供丰富的 Tab 自动补
全功能,进一步方便进行问题的定位和诊断。
安装arthas
详情见: https://www.cnblogs.com/expiator/p/17454838.html
启动示例类:
math-game 是arthas 自带的一个示例类。可以启动后,用于测试。
curl -O https://arthas.aliyun.com/math-game.jar
java -jar math-game.jar
启动 arthas
java -jar arthas-boot.jar
选择 java 进程,输入对应的序号,比如 1,然后按Enter,就可以了。
[INFO] JAVA_HOME: D:\jdk8\jre
[INFO] arthas-boot version: 3.6.9
[INFO] Process 19440 already using port 3658
[INFO] Process 19440 already using port 8563
[INFO] Found existing java process, please choose one and input the serial number of the process, eg : 1. Then hit ENTER.
* [1]: 19440 math-game.jar
[2]: 19744 org.jetbrains.idea.maven.server.RemoteMavenServer36
[3]: 21952 com.intellij.database.remote.RemoteJdbcServer
[4]: 9120 org.jetbrains.jps.cmdline.Launcher
查看 dashboard
输入 dashboard,按回车/enter
,会展示当前进程的信息,按ctrl+c
可以中断执行。
ID: 线程ID
NAME: 线程名
GROUP: 线程组名
PRIORITY: 线程优先级, 1~10之间的数字,越大表示优先级越高
STATE: 线程的状态.
CPU%: 线程的cpu使用率。比如采样间隔1000ms,某个线程的增量cpu时间为100ms,则cpu使用率=100/1000=10%
DELTA_TIME: 上次采样之后线程运行增量CPU时间,数据格式为秒
TIME: 线程运行总CPU时间,数据格式为分:秒
INTERRUPTED: 线程当前的中断位状态
DAEMON: 是否是daemon线程
watch
能够方便的观察到指定函数的调用情况。能观察到的范围为:返回值
、抛出异常
、入参
,通过编写 OGNL 表达式进行对应变量的查看。
在使用 Intellij Idea 进行调试时,有时会用watch() 查看变量的值,arthas的 watch命令作用类似,而且更加强大。
- watch常用的参数:
参数名称 | 参数说明 |
---|---|
class-pattern | 类名表达式匹配 |
method-pattern | 方法名表达式匹配 |
express | 观察表达式 |
condition-express | 条件表达式,满足条件表达式才查看 |
-b | 在方法调用之前观察,before |
-e | 在方法异常之后观察,exception |
-s | 在方法返回之后观察,success |
-f | 在方法结束之后(正常返回和异常返回)观察,finish |
-e | 开启正则表达式匹配,默认为通配符匹配 |
-x | 指定输出结果的属性遍历深度,默认为 1 |
- 查看方法的入参、属性、返回值:
默认情况下,会查看方法的入参、属性、返回值。
watch 包的路径.类名 方法名 "{params, target, returnObj}"
包的路径,一般就是类的代码里面的 package 路径。
假设 某个类的代码里面显示 package com.example.demo; 那么包的路径就是com.example.demo,
如果不确定包的路径,也可以用 *. 匹配,比如 Demo类,就是 *.Demo。
params: 就是方法参数
target: 就是类的属性
returnObj: 返回值。
- 查看方法的参数、返回值。(非常实用)
watch demo.MathGame primeFactors "{params,returnObj}"
- 查看方法的返回值
watch 包的路径.类名 方法名 returnObj
示例:
watch demo.MathGame primeFactors returnObj
- watch使用 -x
-x参数,指遍历深度,默认为1,如果无法查出数值,可以尝试加大遍历深度。
示例:
遍历深度,默认为1。
result=@ArrayList 后面的结果分别对应 "{params, target, returnObj}"
结果只能看到 result 结果中有多少个参数,没法看到参数的具体值。
[arthas@19440]$ watch demo.MathGame primeFactors -x 1
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 14 ms, listenerId: 2
method=demo.MathGame.primeFactors location=AtExceptionExit
ts=2023-06-06 00:09:00; [cost=0.355ms] result=@ArrayList[
@Object[][isEmpty=false;size=1],
@MathGame[demo.MathGame@15f550a],
null,
]
当遍历深度,修改为 2后,显示如下,可以看到 入参数是 1 (也就是下文的 @Integer[1] ), 返回结果的@ArrayList 也能看到list 里面具体的数值(也就是下文的 2,2,2,19,29,47)。
[arthas@19440]$ watch demo.MathGame primeFactors -x 2
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 22 ms, listenerId: 3
method=demo.MathGame.primeFactors location=AtExit
ts=2023-06-06 00:09:03; [cost=0.1013ms] result=@ArrayList[
@Object[][
@Integer[1],
],
@MathGame[
random=@Random[java.util.Random@6b2d4a],
illegalArgumentCount=@Integer[46006],
],
@ArrayList[
@Integer[2],
@Integer[2],
@Integer[2],
@Integer[19],
@Integer[29],
@Integer[47],
],
]
- 只查看满足条件表达式的:
示例,"params[0]<0", 表示只有第一个参数小于0时,才查看数据。
[arthas@19440]$ watch demo.MathGame primeFactors "{params,returnObj}" "params[0]<0" -x 2
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 21 ms, listenerId: 2
method=demo.MathGame.primeFactors location=AtExceptionExit
ts=2023-06-06 22:47:07; [cost=0.102ms] result=@ArrayList[
@Object[][
@Integer[-81071],
],
null,
]
- 查看异常:
通过 "{params,throwExp}" 查看异常。
[arthas@19440]$ watch demo.MathGame primeFactors "{params,throwExp}" -e -x 2
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 22 ms, listenerId: 4
method=demo.MathGame.primeFactors location=AtExceptionExit
ts=2023-06-06 22:52:41; [cost=0.1559ms] result=@ArrayList[
@Integer[-49317],
java.lang.IllegalArgumentException: number is: -49317, need >= 2
at demo.MathGame.primeFactors(MathGame.java:46)
at demo.MathGame.run(MathGame.java:24)
at demo.MathGame.main(MathGame.java:16)
,
]
- 根据耗时查看:
#cost>200
(单位是ms
)表示只有当耗时大于 200ms 时才会输出,过滤掉执行时间小于 200ms 的调用;
$ watch demo.MathGame primeFactors '{params, returnObj}' '#cost>200' -x 2
Press Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 66 ms.
ts=2018-12-03 19:40:28; [cost=2112.168897ms] result=@ArrayList[
@Object[][
@Integer[1],
],
@ArrayList[
@Integer[5],
@Integer[428379493],
],
]
- 观察当前对象中的属性
如果想查看函数运行前后,当前对象中的属性,可以使用target
关键字,代表当前对象
$ watch demo.MathGame primeFactors 'target'
Press Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 52 ms.
ts=2018-12-03 19:41:52; [cost=0.477882ms] result=@MathGame[
random=@Random[java.util.Random@522b408a],
illegalArgumentCount=@Integer[13355],
]
然后使用target.field_name
访问当前对象的某个属性
$ watch demo.MathGame primeFactors 'target.illegalArgumentCount'
Press Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 67 ms.
ts=2018-12-03 20:04:34; [cost=131.303498ms] result=@Integer[8]
ts=2018-12-03 20:04:35; [cost=0.961441ms] result=@Integer[8]
退出 arthas
- exit
如果只是退出当前的连接,可以用quit
或者exit
命令。
Attach 到目标进程上的 arthas 还会继续运行,端口会保持开放,下次连接时可以直接连接上。
- stop
关闭 Arthas 服务端,所有 Arthas 客户端全部退出。
停止已存在的Arthas实例:
java -jar arthas-client.jar 127.0.0.1 3658 -c "stop"
参考资料:
Arthas使用教程(8大分类)_arthas教程_ha_lydms的博客-CSDN博客watch | arthas死磕JVM | 用Arthas排查JVM内存 真爽!-51CTO.COM