导图社区 arthas:Java调试利器,线上Debug不是梦
arthas使用指南,如常见问题 如何查看一个class类的具体信息?jad反编译一个类,也可以指定到具体类中具体的方法。
编辑于2023-10-11 11:06:12Arthas学习
使用场景
这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?<br>
我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?<br>
遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?<br>
线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!<br>
是否有一个全局视角来查看系统的运行状况?<br>
有什么办法可以监控到JVM的实时运行状态?<br>
怎么快速定位应用的热点,生成火焰图?
快速安装
curl -O https://arthas.aliyun.com/arthas-boot.jar
快速启动
java -jar arthas-boot.jar
启动成功之后,会在 ~/.arthas/lib/ 目录下,下载相应版本依赖包
如果不成功,可以查看~/logs/arthas/ 目录下的日志
如果下载速度比较慢,可以使用aliyun的镜像:java -jar arthas-boot.jar --repo-mirror aliyun --use-http<br>
java -jar arthas-boot.jar -h 使用该命令,可以查看更多帮助信息
远程访问
java -jar arthas-boot.jar --target-ip 0.0.0.0
浏览器远程访问: http://ip:8563<br>
- ip地址为arthas所在机器ip - 端口为/Users/yangwenpeng/.arthas/lib/3.4.6/arthas/arthas.properties中arthas.httpPort配置项
离线安装
1. 将启动之后的lib目录依赖包打包,部署到离线环境节点的 ~/.arthas 目录下<br>2. 复制arthas-boot.jar 部署到离线环境节点中<br>3. 参考快速启动步骤使用arthas
快速卸载
rm -rf ~/.arthas/ rm -rf ~/logs/arthas
常用命令
dashboard
- ID: Java级别的线程ID,注意这个ID不能跟jstack中的nativeID一一对应 - NAME: 线程名 - GROUP: 线程组名 - PRIORITY: 线程优先级, 1~10之间的数字,越大表示优先级越高 - STATE: 线程的状态 - CPU%: 线程消耗的cpu占比,采样100ms,将所有线程在这100ms内的cpu使用量求和,再算出每个线程的cpu使用占比。 - DELTA_TIME: 上次采样之后线程运行增量CPU时间,数据格式为秒 - TIME: 线程运行总时间,数据格式为分:秒 - INTERRUPTED: 线程当前的中断位状态 - DAEMON: 是否是daemon线程
可以查看系统的实时数据面板
q 或 ctrl+c 可以退出数据面展示
-i 指定命令执行间隔,默认5000毫秒<br> -n 指定命令执行次数
dashboard dashboard -n 10 dashboard -i 2000
thread
- 没有线程ID,包含[Internal]表示为JVM内部线程,参考dashboard命令的介绍。 - cpuUsage为采样间隔时间内线程的CPU使用率,与dashboard命令的数据一致。 - deltaTime为采样间隔时间内线程的增量CPU时间,小于1ms时被取整显示为0ms。 - time 线程运行总CPU时间。
查看当前线程信息,查看线程的堆栈
id 指定线程id<br>-n 指定最忙的前N个线程并打印堆栈<br>-b 找出当前阻塞其他线程的线程(注意, 目前只支持找出synchronized关键字阻塞住的线程, 如果是java.util.concurrent.Lock, 目前还不支持。)<br>-i 指定cpu使用率统计的采样间隔,单位为毫秒,默认值为200
thread -i 1000 : 统计最近1000ms内的线程CPU时间。 thread -n 3 -i 1000 : 列出1000ms内最忙的3个线程栈
当没有参数时,显示第一页线程的信息,默认按照CPU增量时间降序排列
jvm
- COUNT: JVM当前活跃的线程数 - DAEMON-COUNT: JVM当前活跃的守护线程数 - PEAK-COUNT: 从JVM启动开始曾经活着的最大线程数 - STARTED-COUNT: 从JVM启动开始总共启动过的线程次数 - DEADLOCK-COUNT: JVM当前死锁的线程数 - MAX-FILE-DESCRIPTOR-COUNT:JVM进程最大可以打开的文件描述符数 - OPEN-FILE-DESCRIPTOR-COUNT:JVM当前打开的文件描述符数
查看当前JVM信息
sysprop
查看当前JVM的系统属性(System Property)
sysenv
查看当前JVM的环境属性(System Environment Variables)
vmoption
查看,更新VM诊断相关的参数
logger
查看logger信息,更新logger level
logger -n 查看指定名字的logger信息
logger -c 手动输入hashcode:-c <hashcode> 查看指定classloader的logger信息
logger --name ROOT --level debug 更新日志级别
logger --include-no-appender 默认情况下,logger命令只打印有appender的logger的信息。如果想查看没有appender的logger的信息
sc
Search-Class 的简写,这个命令能搜索出所有已经加载到 JVM 中的 Class 信息
-d 参数可以打印出类加载的具体信息,方便定位类加载问题
-f 输出当前类的成员变量信息(需要配合参数-d一起使用)
sm
Search-Method的简写,查看已加载类的方法信息
sm java.lang.String
sm -d java.lang.String toString
jad
将 JVM 中实际运行的 class 的 byte code 反编译成 java 代码,便于你理解业务逻辑
jad java.lang.String
反编译时只显示源代码 jad --source-only demo.MathGame
反编译指定的函数 jad demo.MathGame main
反编译时不显示行号 jad --lineNumber false demo.MathGame
mc
Memory Compiler/内存编译器,编译.java文件生成.class
mc /tmp/Test.java
可以通过-c参数指定classloader: mc -c 327a647b /tmp/Test.java<br>
可以通过-d命令指定输出目录: mc -d /tmp/output /tmp/ClassA.java /tmp/ClassB.java
retransform
加载外部的.class文件,retransform jvm已加载的类
指定的 .class 文件<br>retransform /tmp/MathGame.class<br>
watch
方便的观察到指定方法的调用情况。能观察到的范围为:返回值、抛出异常、入参,通过编写 OGNL 表达式进行对应变量的查看
-b 在方法调用之前观察
-e 在方法异常之后观察
-s 在方法返回之后观察
-f 在方法结果之后观察,默认打开,前面3个默认关闭
-x 指定输出结果的属性遍历深度
watch org.apache.knox.gateway.util.urltemplate.Parser parseLiteral "params,returnObj" "params[0].indexOf('zeppelin')>-1" -x 2 -n 10
profiler
生成应用热点的火焰图。本质上是通过不断的采样,然后把收集到的采样结果生成火焰图。
profiler start 默认情况下,生成的是cpu的火焰图,即event为cpu。可以用--event参数来指定。
profiler getSamples 获取已采集的sample的数量
profiler stop 停止采样,默认情况下,生成的结果保存到应用的工作目录下的arthas-output目录。可以通过 --file参数来指定输出结果路径
profiler stop --file /tmp/output.svg
profiler stop --format html
profiler stop --file /tmp/result.html
http://localhost:3658/arthas-output/
常见问题
问题1. 我如何查找某个只知道大概的类,或者说我想确认某个类是否已被系统加载?
通过通配符 * 匹配,也可以 *XXX* 格式匹配
问题2. 如何查看一个class类的具体信息?
jad反编译一个类,也可以指定到具体类中具体的方法
watch com.aurora.jvm.MathGame primeFactors "{params, returnObj, throwExp}" -e -x 2 # 同时监控入参,返回值,及异常
问题3. 如何跟踪某个方法的返回值、入参.... ?
watch 命令结合ognl表达式
问题4. 查看最繁忙的线程,以及是否有阻塞情况发生?
thread -n 3 # 查看最繁忙的三个线程栈信息
thread # 以直观的方式展现所有的线程情况
thread -b #找出当前阻塞其他线程的线程
问题5. 如何验证自己的代码猜想,临时更改代码运行?
1. 然后使用外部工具编辑内容<br>jad --source-only com.example.demo.arthas.user.UserController > /tmp/UserController.java<br>2. 然后使用外部工具编辑内容,再编译成class<br>mc /tmp/UserController.java -d /tmp<br>3. 重新载入定义的类,就可以实时验证修改的代码<br>redefine /tmp/com/example/demo/arthas/user/UserController.class
问题6. 如何测试某个方法的性能问题?
monitor -c 5 com.aurora.jvm.MathGame primeFactors
问题7. 其他的追踪方法
tt -t com.aurora.jvm.MathGame primeFactors # 追踪方法的响应时间情况
trace com.aurora.jvm.MathGame run '#cost > 10' # 据调用耗时过滤