Alibaba开源的Java诊断工具
1.支持管道操作;2.-h
查看帮助;3.tab
自动补全;4.keymap查看快捷键;5.方向键上和下查看历史命令,或通过history命令
1.启动需要监测的应用程序
2.启动arthas,attach到自己的程序上
1 | wget https://alibaba.github.io/arthas/arthas-boot.jar |
3.输入序号,回车。attach成功后,会打印Logo
常用命令
dashboard
:查看当前系统的实时数据面板
thread
:打印线程栈信息thread [id]
jad
:反编译代码jad demo.MathGame
watch
:查看函数的参数/返回值/异常信息watch demo.MathGame primeFactors returnObj
sc
:查找JVM里已加载的类sc -d *MathGame
exit
或quit
:退出当前session
shutdown
:停止程序
resert
:清除增强代码(Arthas在 watch/trace 等命令时,实际上是修改了应用的字节码,插入增强的代码。)
参数
--target-ip
:允许外部访问
--versions
:列出所有版本
--use-version 3.1.0
:使用指定版本
telnet-port 9999 --http-port -1
:只监听Telnet端口,不监听HTTP端口
-v
:打印运行详情
查看JVM信息
sysprop
打印所有的System Properties信息
也可以指定单个key: sysprop java.version
也可以通过grep
来过滤: sysprop | grep user
可以设置新的value: sysprop testKey testValue
sysenv
sysenv
命令可以获取到环境变量。和sysprop
命令类似。
jvm
jvm
命令会打印出JVM
的各种详细信息。
dashboard
dashboard
命令可以查看当前系统的实时数据面板。
输入 Q
或者 Ctrl+C
可以退出dashboard命令。
sc/sm 查看已加载的类
sc
sc
命令可以查找到所有JVM已经加载到的类。
如果搜索的是接口,还会搜索所有的实现类。比如查看所有的Filter
实现类:
1 | sc javax.servlet.Filter |
通过-d
参数,可以打印出类加载的具体信息,很方便查找类加载问题。
1 | sc -d javax.servlet.Filter |
sc
支持通配,比如搜索所有的StringUtils
:
1 | sc *StringUtils |
sm
sm
命令则是查找类的具体函数。比如:
1 | sm java.math.RoundingMode |
通过-d
参数可以打印函数的具体属性:
1 | sm -d java.math.RoundingMode |
也可以查找特定的函数,比如查找构造函数:
1 | sm java.math.RoundingMode <init> |
Jad
可以通过 jad
命令来反编译代码:
1 | jad com.example.demo.arthas.user.UserController |
通过--source-only
参数可以只打印出在反编译的源代码:
1 | jad --source-only com.example.demo.arthas.user.UserController |
Ognl
在Arthas里,有一个单独的ognl
命令,可以动态执行代码。
调用static函数
1 | ognl '@java.lang.System@out.println("hello ognl")' |
获取静态类的静态字段
获取UserController
类里的logger
字段:
1 | ognl -c 1be6f5c3 @com.example.demo.arthas.user.UserController@logger |
还可以通过-x
参数控制返回值的展开层数。比如:
1 | ognl -c 1be6f5c3 -x 2 @com.example.demo.arthas.user.UserController@logger |
执行多行表达式,赋值给临时变量,返回一个List
1 | $ ognl '#value1=@System@getProperty("java.home"), #value2=@System@getProperty("java.runtime.name"), {#value1, #value2}' |
更多
在Arthas里ognl
表达式是很重要的功能,在很多命令里都可以使用ognl
表达式。
一些更复杂的用法,可以参考:
- OGNL特殊用法请参考:https://github.com/alibaba/arthas/issues/71
- OGNL表达式官方指南:https://commons.apache.org/proper/commons-ognl/language-guide.html
trace
trace 命令能主动搜索 class-pattern/method-pattern 对应的方法调用路径,渲染和统计整个调用链路上的所有性能开销和追踪调用链路。
但是trace只能追踪一层的调用链路,如果一层的链路信息不够用,可以把该链路上有问题的方法再次进行trace。
trace使用例子如下。
trace demo.MathGame primeFactors
tt
录制、回放请求。有时候排查一个问题需要上游再次调用这个方法,比如使用postMan等工具,当然Arthas提供了一个命令让替代来回手动请求。
录制:tt -t demo.MathGame primeFactors
回放:tt -i 1004 -p
注意重放请求需要关注两点:
- ThreadLocal 信息丢失:由于使用的是Arthas线程调用,会让threadLocal信息丢失,比如一些TraceId信息可能会丢失
- 引用的对象:保存的入参是保存的引用,而不是拷贝,所以如果参数中的内容被修改,那么入参其实也是被修改的。
查看调用
有时候有些方法非常耗时或者非常重要,需要知道到底是谁发起的调用,比如System.gc(),有时候如果发现fullgc频繁是因为System.gc()引起的,需要查看到底是什么应用调用的。
1 | options unsafe true |
首先输入options unsafe true允许对jdk增强,然后对System.gc进行进行监视,然后记录当前的堆栈来获取是什么位置进行的调用。
实践
概述
watch com.xxx.UserController * '{params,throwExp} -x 2
结构:watch 类名 函数名 返回值表达式 展开结果
返回值表达式可选值如下:
- loader
- clazz
- method
- target
- params
- returnObj
- throwExp
- isBefore
- isThrow
- isReturn
条件表达式
当第一个参数大于100时才打印结果
watch com.example.demo.arthas.user.UserController * returnObj 'params[0] > 100
捕获异常
watch
命令支持-e
选项,表示只捕获抛出异常时的请求:
1 | watch com.example.demo.arthas.user.UserController * "{params[0],throwExp}" -e |
按照耗时进行过滤
watch
命令支持按请求耗时进行过滤,比如:
1 | watch com.example.demo.arthas.user.UserController * '{params, returnObj}' '#cost>200' |
热更新代码
保存反编译文件
jad --source-only com.example.demo.arthas.user.UserController > /tmp/UserController.java
查找ClassLoader
1 | sc -d *UserController | grep classLoaderHash |
修改反编译文件后,重新编译
1 | mc -c 1be6f5c3 /tmp/UserController.java -d /tmp |
重新加载新编译后的文件
1 | redefine /tmp/com/example/demo/arthas/user/UserController.class |
动态更新日志级别
查找ClassLoader
1 | sc -d com.example.demo.arthas.user.UserController | grep classLoaderHash |
用ognl获取logger
1 | ognl -c 1be6f5c3 '@com.example.demo.arthas.user.UserController@logger' |
可以通过loggerContext看出来使用的是logback,并且通过level看出来没有设置级别
单独设置某类的级别
1 | ognl -c 1be6f5c3 '@com.example.demo.arthas.user.UserController@logger.setLevel(@ch.qos.logback.classic.Level@DEBUG)' |
修改全局日志级别
1 | ognl -c 1be6f5c3 '@org.slf4j.LoggerFactory@getLogger("root").setLevel(@ch.qos.logback.classic.Level@DEBUG)' |
线程
查看所有线程信息
1 | thread |
查看具体线程的栈
查看线程ID 16的栈:
1 | thread 16 |
查看CPU使用率top n线程的栈
1 | thread -n 3 |
查看5秒内的CPU使用率top n线程栈
1 | thread -n 3 -i 5000 |
查找线程是否有阻塞
1 | thread -b |
Web Console
通过Web Socket访问Arthas:http://localhost:8563
原理
SC
主要信息,通过Class获取:Test.class.isInterface()
加载信息,通过CodeSource获取:
1 | CodeSource codeSource = Test.class.getProtectionDomain().getCodeSource(); |
jad
使用的是cfr提供的jar包来进行反编译
修改日志级别
具体原理是首先获取AppClassLoader(默认)或者指定的ClassLoader,然后再调用Ognl的包,自动执行解析这个表达式,而这个执行的类都会从前面的ClassLoader中获取中去获取。
watch
利用jdk1.6的instrument + ASM 记录方法的入参出参,以及方法消耗时间。
trace
利用jdk1.6的instrument + ASM。在访问方法之前和之后会进行记录