一、概述
可以解决问题:
- 这个类是哪个jar包加载的?为什么会报各种类相关的Exception
- 我改的代码为什么没有执行?
- 遇到线上问题无法debug,难道只能通过加日志重新发布吗?
- 线上遇到某个用户的数据处理有问题,线下无法重现
- 是否有一个全局视角来查看系统的运行状况?
- 有什么办法可以监控到JVM的实时运行状态?
- 怎么养快速定位应用的热点,火焰图
运行环境要求,JDK6以上的版本,支持Tab自动补全功能,命令行的交互模式。
二、快速安装
去官网下载:下载 — Arthas 3.5.5 文档
简单命令:
- java -jar arthas-boot.jar:启动
- java -jar arthas-boot.jar -h:查看帮助文档,其实可以去官网查看
绿色软件,卸载的时候,直接删除即可。
三、快速入门
1、粘附一个进程
出现如下异常,增加JVM启动参数:-XX:+StartAttachListener,同时注意用户权限问题。
如果端口占用,可以使用:
java -jar arthas-boot.jar --telnet-port 端口号 --http-port -1
也可直接跟着进程ID,进行粘附。也可在浏览器上进行操作,但是端口号需要开放。
四、基础命令
1、dashboard 仪表盘
2、thread命令查看 main class
可以使用:thread 线程ID,查看线程运行状态 :
3、jad 反编译
包含类所使用的类加载器、所在的jar包、源码。
4、watch:查看方法在执行过程中的入参、出参
5、退出arthas
- quit、exit:关闭当前操作界面,绘画保持
- stop:退出回话,关闭进程
五、Arthas命令行快捷键
1、基础命令1
- help:帮助文档
- cat:同linux下一样的意思,查看某个文件内容
- grep:管道命令,过滤作用
- -n:显示行号
- -i:忽略大小学
- -m:最多显示多少行
- -e:正则表达式
- pwd:查看路径
- cls:清屏
2、基础命令2
- session:查看当前回话信息
- reset:还原增强的类
- version:查看arthas版本号
- history:查看输入的历史命令
- quit:退出当前session,不影响其它会话
- stop:停止当前的arthas服务
- keymap: 显示arthas的快捷键
六、JVM相关
1、dashboard
从上至下分别是:
- 线程相关
- ID:线程ID
- NAME:线程名字
- GROUP:线程组
- PRIORITY:线程优先级
- STATE:线程状态
- %CPU:cpu占比
- TIME:运行时间。分钟:秒
- INTERRUPTE:中断状态
- DAEMON:是否是守护线程
- 内存相关
- Memroy:内存区域
- used:使用的内存
- total:总内存
- max:最大内存
- usage:使用百分比
- GC:垃圾回收机制
- 运行环境
2、thread(重要)
参数:
- 数字:线程ID
- n:前n个最忙的线程堆栈信息
- b:找出当前阻塞其它线程的线程
- i <vaue>:制定CPU占比统计采样间隔,单位为毫秒
- 查看某种状态的所有线程
3、jvm
4、sysprop
查看java虚拟机属性,可以修改。
5、sysenv
查看jvm环境属性
6、vmoption
查看、更新JVM诊断相关参数
7、getstatic
获取静态属性,getstatic 类名 属性名
8、ognl
执行ognl表达式,但是要学习ognl语法
1、调用静态方法 ognl '@java.lang.System@out.println("go go")'
2、获取静态字段 ognl '@demo.MathGame@random'
3、执行多行表达式,赋值给临时变量,返回一个list
ognl '#value1=@System@getProperty("java.home"),#value2=@System@getProperty("java.runtime.name"),{#value1,#value2}'
七、class\classloader相关
1、sc
Search Class 的缩写,在jvm中检索已经加载的某个类的信息,默认查询子类
2、sm
Search method 检索方法,无法看到父类的方法
3、jad
字节码文件反编译成源代码
反编译某个方法:
4、mc
源代码编译成字节码
5、redefine
加载外部的.class文件,redefine到JVM中。
注意:redefine后的原来的类不能恢复,redefine可能失败(增加的field)。reset对redefine的类无效。如果想要重置,则需要redefine原始的字节码。会和jad/watch/trace/monitor/tt等命令冲突。执行以上命令会重置redefine的字节码重置。
限制:
- 不允许新增field和method
- 正在运行的函数,没有推出不能生效
6、dump
正在运行的类的字节码文件保存到某个目录下
7、classloader
获取类加载器的信息
八、monitor\watch\trace相关
1、monitor
监视指定时间段内一个类的方法执行情况,默认120秒坚实一次,非实时显示命令
monitor -c 5 demo.MathGame primeFactors
2、watch(因为支持ognl表达式,能够看到方法内部执行的情况)
在诊断程序过程中,使用比较多的。检测方法的执行情况,入参、返回值、异常、出参等,并且可以使用ognl查看对应变量的值。
说明:
- watch定义了4个观察时间点,即-b方法调用前、-e方法异常后、-s方法返回后、-f方法结束后
- 4个观察事件点-b、-e、-s默认关闭,-f默认打开,当指定观察点被打开后,在相应时间点会对观察表达式进行求值并输出
- 这里要注意方法入参和出参的区别,参数可能在执行过程中被修改了,除了-b观察点params代表入参,其它时间点都代表出参
- 当使用-b时,由于观察事件点在方法调用前,所以返回值或者异常都不存在
案例:
1、监控方法出参和返回值,属性遍历深度为2
watch demo.MathGame primeFactors "{params,returnObj}" -x 2
2、观察方法的入参,因为观察点是执行前,所以只能看到入参,无法看到返回值
watch demo.MathGame primeFactors "{params,returnObj}" -x 2 -b
3、观察调用方法的对象属性,查看方法执行前后,当前对象中的属性,可以使用traget关键字,表示当前对象
watch demo.MathGame primeFactors "traget" -x 2 -b
4、查看对象的属性
watch demo.MathGame primeFactors "target.illegalArgumentCount" -x 2
5、方法调用前后,参数的不同,执行2次
watch demo.MathGame primeFactors "{params,target,returnObj}" -x 2 -b -s -n 2
6、查看第一个参数小于0的情况
watch demo.MathGame primeFactors "{params[0],target}" "params[0]<0" -x 2 -b
3、trace
对于方法内部调用路径进行追踪,并输出每个节点上的耗时。
1、查看某个方法的运行情况,只补货2次运行结果
trace demo.MathGame run -n 2
2、跳过jdk执行的方法
trace --skipJDKMethod false demo.MathGame run -n 2
3、对耗时进行筛选
trace demo.MathGame run -n 2 '#cost >.5'
4、stack
输出当前方法被调用的调用路径
1、查看方法的输出路径,2次
stack demo.MathGame primeFactors -n 2
2、条件表达式,第0个参数小于0
stack demo.MathGame primeFactors 'params[0]<0' -n 2
3、耗时
stack demo.MathGame primeFactors 'params[0]<0 and #cost>0.5' -n 2
5、tt
time-tunnel 时间隧道,记录指定方法每次调用的入参和返回信息,并对这些不同的时间调用的信息进行观测。watch需要会ognl表达式,所以有些时候不那么好用。
说明:
- 支持条件表达式
- 解决方法重载
- tt -t *Test print params.length==1,指定参数个数
- tt -t *Test print params[1] instanceof Interger 指定参数类型
- 指定参数值
- tt -t *Test print params[0].mobile="13103000103"
1、调用某个方法的时间隧道
tt -t demo.MathGame primeFactors
2、 检索时间片段,显示之前记录的全部时间隧道
tt -l
tt -s 'method.name=="xxx"'
tt -i 1010:查看索引为某次的调用
tt -i 1010 -p --replay-times 3 --replay-interval 2:重新调用
5、火焰图 profiler
生成火焰图,使用步骤:
- 启动:profiler start,每隔时间多JVM进行采集
- 获取采集样本:profiler getSamples
- 查看当前获取状态:profiler stastus
- 停止:profiler stop
6、option
arthas全局选项配置
九、实践:哪个Controller处理了请求
需求:
1、确定哪个controller处理了请求?
trace org.springframework.web.servlet.DispatcherServlet *
jad org.springframework.web.servlet.DispatcherServlet 查看到 方法getHandler
以上其实如果熟悉spring mvc 的源码,直接就能定位到。
watch org.springframework.web.servlet.DispatcherServlet getHandler '{params,returnObj}' -x 2
2、每个请求调用的参数和返回值是多少?
经过以上操作,就能看到这个请求具体调用应用里面的代码是哪个了。可以看到参数为空,返回值也为空,中间是target调用方法的对象。
十、总结
简单把arthas工具学习了一下。感谢黑马的老师的讲解。
- JVM的排查:可以看到thread的运行情况,对于线程的排查理论上可以替代jstack,但是如果需要优化,则还是需要使用工具对dump文件进行分析。没看官网,不清楚arthas是否有这类的功能,但是应该没有一些图形化界面好用
- GC的排查:理论上应该没有gceasy一类的工具好用,是否有功能不确定
- 请求流程的排查:只能说牛逼,但是需要熟悉OGNL表达式,能够实时的查看方法的执行情况、流程、耗时等,并且能够对代码进行反编译和增强。
最后还是需要在实际环境中多用用,还有需要书序OGNL。这样能更方便的写出追踪语句。
idea插件 arthas-idea-plugin/README.md at master · WangJi92/arthas-idea-plugin · GitHub