Arthas
github :https://github.com/alibaba/arthas
Arthas 是Alibaba开源的Java诊断工具,采用命令行交互模式,是排查jvm相关问题的利器。
下载安装
curl -O https://alibaba.github.io/arthas/arthas-boot.jar
java -jar arthas-boot.jar
# 然后可以选择一个Java进程
常用命令
具体每个命令怎么使用,大家可以自己查阅资料
version:查看arthas版本号
help:查看命名帮助信息
cls:清空屏幕
session:查看当前会话信息
quit:退出arthas客户端
---
dashboard:当前进程的实时数据面板
thread:当前JVM的线程堆栈信息
jvm:查看当前JVM的信息
sysprop:查看JVM的系统属性
---
sc:查看JVM已经加载的类信息
dump:dump已经加载类的byte code到特定目录
jad:反编译指定已加载类的源码
---
monitor:方法执行监控
watch:方法执行数据观测
trace:方法内部调用路径,并输出方法路径上的每个节点上耗时
stack:输出当前方法被调用的调用路径
......
下面我们看一些Arthas常用命令
问题1. 如何查找某个只知道大概的类,或者说想确认某个类是否已被系统加载,又或者说想确认加载的某个类属于哪个包?
sc *StringUtil # 即可以找到需要的类全路径,如果存在的话
sc -d org.springframework.web.servlet.DispatcherServlet # 查看某个类的信息,如果存在的话
sm org.springframework.web.servlet.DispatcherServlet getHandler # 查看某个方法的信息,如果存在的话
使用通配符列出所有的方法:命令:sm
问题2. 如何查看一个class的具体信息,或者说如何反编译class文件?
jad java.lang.String # 反编译出java源代码
问题3. 如何跟踪某个方法的返回值、入参… ?
watch 让你能方便地观察到指定方法的调用情况。能观察到的范围为:入参、返回值、抛出异常
USAGE:
watch [-b] [-e] [-x <value>] [-f] [-h] [-n <value>] [--listenerId <value>] [-E] [-M <value>] [-s] [-v] class-patter n method-pattern [express] [condition-express]
Examples:
watch -b org.apache.commons.lang.StringUtils isBlank params
watch -f org.apache.commons.lang.StringUtils isBlank returnObj
watch org.apache.commons.lang.StringUtils isBlank '{params, target, returnObj}' -x 2
watch -bf *StringUtils isBlank params
watch *StringUtils isBlank params[0]
watch *StringUtils isBlank params[0] params[0].length==1
watch *StringUtils isBlank params '#cost>100'
watch -E -b org\.apache\.commons\.lang\.StringUtils isBlank params[0]
1. 观察方法返回结果 returnObj
使用方式看着复杂,其实很简单。来个最简单的示例: 假设我们要观察下面这段代码中字符串的contains
方法。
public class App {
public static void main(String[] args) throws IOException {
String hello = "Hello Arthas";
while (true) {
boolean contains = StringUtils.contains(hello, "Arthas");
System.out.println(contains);
}
}
}
可以使用如下语句:
## 观察 contains 返回结果
[arthas@76792]$ watch org.apache.commons.lang3.StringUtils contains returnObj -n 3
# Press Q or Ctrl+C to abort.
# Affect(class-cnt:1 , method-cnt:2) cost in 68 ms.
# ts=2020-05-02 16:46:04; [cost=2.424254ms] result=@Boolean[true]
# ts=2020-05-02 16:46:05; [cost=0.21033ms] result=@Boolean[true]
# ts=2020-05-02 16:46:06; [cost=0.165514ms] result=@Boolean[true]
-n 3
表示只执行三次,这参数挺常用,不然很容易被输出刷屏。
2. 过滤不关心的调用 condition-express
显然,真实的案例肯定不会如上面的示例那么简单。 真实的服务代码中,肯定不止一个地方调用了String的contains
方法。我们需要把无关的调用过滤掉。
## 观察 contains 返回结果,并且过滤掉无关调用
[arthas@76792]$ watch org.apache.commons.lang3.StringUtils contains returnObj 'params[1]=="Arthas"'
# Press Q or Ctrl+C to abort.
# Affect(class-cnt:1 , method-cnt:2) cost in 29 ms.
# ts=2020-05-02 16:48:50; [cost=0.331109ms] result=@Boolean[true]
# ts=2020-05-02 16:48:51; [cost=0.175224ms] result=@Boolean[true]
# ts=2020-05-02 16:48:52; [cost=0.138984ms] result=@Boolean[true]
入参是一个很容易把不同调用区分开的方法,通过params[1]=="Arthas"
这个condition-express
,我们可以只保留第二个入参是Arthas
的函数调用。
3. 同时观察入参和结果
[arthas@76792]$ watch org.apache.commons.lang3.StringUtils contains {params,returnObj} 'params[1]=="Arthas"'
# Press Q or Ctrl+C to abort.
# Affect(class-cnt:1 , method-cnt:2) cost in 33 ms.
# ts=2020-05-02 16:51:27; [cost=0.507486ms] result=@ArrayList[
# @Object[][isEmpty=false;size=2],
# @Boolean[true],
# ]
通过 {}
把字段包起来,可以同时观察想观察的字段。可以注意到一个点,params
是一个数组,但是打印 params
的时候并没有把具体内容打印出来,这个时候可以使用 -x 2
来指定打印对象的属性遍历深度。
arthas@76792]$ watch org.apache.commons.lang3.StringUtils contains {params,returnObj} 'params[1]=="Arthas"' -x 2
# Press Q or Ctrl+C to abort.
# Affect(class-cnt:1 , method-cnt:2) cost in 35 ms.
# ts=2020-05-02 16:51:33; [cost=0.391218ms] result=@ArrayList[
# @Object[][
# @String[Hello Arthas],
# @String[Arthas],
# ],
# @Boolean[true],
# ]
再举例子说明 -x 2
来指定打印对象的属性遍历深度
问题4. 查看最繁忙的线程,以及是否有阻塞情况发生?
thread -n 3 # 查看最繁忙的三个线程栈信息
thread # 以直观的方式展现所有的线程情况
thread -b #找出当前阻塞其他线程的线程
问题5. 如何验证自己的代码猜想,临时更改代码运行?
jad --source-only com.example.demo.arthas.user.UserController > /tmp/UserController.java # 先反编译出class源码
# 然后使用外部工具编辑内容
mc /tmp/UserController.java -d /tmp # 再编译成class
# 最后,重新载入定义的类,就可以实时验证你的猜测了
redefine /tmp/com/example/demo/arthas/user/UserController.class
如上,是直接更改线上代码的方式,但是一般好像是编译不成功的。所以,最好是 本地ide 编译成 class 文件后,再上传替换为好!
问题6. 我如何测试某个方法的性能问题?
monitor com.telek.business.statistics.util.tools.DzjcUtil sortByNumber -c 5
问题7. 如果内存满了,想分析内存怎么办?
heapdump [-h] [-l] [file]
到这那么问题来了,堆快照导出来了,之后怎么分析?
上工具:MemoryAnalyzer(MAT)
1、下载MAT
MAT是使用非常广泛的Java内存分析工具,功能强大;
(1)官网下载:https://www.eclipse.org/mat/downloads.php
(2)解压后配置,如果快照文件太大可以通过配置该文件,默认:-Xmx1024m
(3)运行
2、MAT打开分析HPROF文件