Arthas 简介

Arthas 是 Alibaba 开源的 Java 诊断工具,根据官方介绍,它提供了如下工功能:

官方文档地址: https://alibaba.github.io/arthas/

github 源码地址: https://github.com/alibaba/arthas

Arthas 安装

启动 Arthas

# 下载 arthas
curl -O https://alibaba.github.io/arthas/arthas-boot.jar
# 通过如下命令启动
java -jar arthas-boot.jar

选择进程 id 按下回车,就可以连接到对应的 java 应用,首次启动会下载一些文件到 "C:/Users/${user}/.arthas/lib/3.2.0/arthas" 目录

arthas 启动支持多个参数,可以使用 -h 查看

EXAMPLES:
java -jar arthas-boot.jar <pid>
java -jar arthas-boot.jar --target-ip 0.0.0.0
java -jar arthas-boot.jar --telnet-port 9999 --http-port -1
java -jar arthas-boot.jar --tunnel-server 'ws://192.168.10.11:7777/ws'
java -jar arthas-boot.jar --tunnel-server 'ws://192.168.10.11:7777/ws'
--agent-id bvDOe8XbTM2pQWjF4cfw
java -jar arthas-boot.jar --stat-url 'http://192.168.10.11:8080/api/stat'
java -jar arthas-boot.jar -c 'sysprop; thread' <pid>
java -jar arthas-boot.jar -f batch.as <pid>
java -jar arthas-boot.jar --use-version 3.2.0
java -jar arthas-boot.jar --versions
java -jar arthas-boot.jar --session-timeout 3600
java -jar arthas-boot.jar --attach-only
java -jar arthas-boot.jar --repo-mirror aliyun --use-http
WIKI:
https://alibaba.github.io/arthas

help

arthas 连接成功后,使用 help 可以看到提供的一些命令

每个命令可以使用 -h 参数查看帮助信息,里面有EXAMPLESWIKI链接

webconsole

arthas 启动后,可以通过浏览器进行访问,地址 http://localhost:8563/

退出

如果只是退出当前的连接,可以用quit或者exit命令。Attach到目标进程上的arthas还会继续运行,端口会保持开放,下次连接时可以直接连接上。

如果想完全退出arthas,可以执行stop命令。

Arthas 命令

dashboard

查看面板信息,主要包含cpu 内存使用信息,可以按 Ctrl+C 或者 输入 q 退出

数据说明

  • ID: Java级别的线程ID,注意这个ID不能跟jstack中的nativeID一一对应
  • NAME: 线程名
  • GROUP: 线程组名
  • PRIORITY: 线程优先级, 1~10之间的数字,越大表示优先级越高
  • STATE: 线程的状态
  • CPU%: 线程消耗的cpu占比,采样100ms,将所有线程在这100ms内的cpu使用量求和,再算出每个线程的cpu使用占比。
  • TIME: 线程运行总时间,数据格式为分:秒
  • INTERRUPTED: 线程当前的中断位状态
  • DAEMON: 是否是daemon线程

thread

查看线程使用情况

# 查看所有线程信息
thread
# 查看具体线程的栈,查看线程ID 16的栈:
thread 16
# 查看CPU使用率top n线程的栈
thread -n 3
# 查看5秒内的CPU使用率top n线程栈
thread -n 3 -i 5000
# 查找线程是否有阻塞
thread -b

sysprop

查看当前JVM的系统属性,支持 pipeline

sysprop # 查询所有属性
sysprop key # 查看key对应的属性
sysprop key value # 修改属性值
sysprop | grep java # 查询包含java的属性
sysprop | wc -l # 统计数量

sysenv

查看当前JVM的环境属性

用法和 sysprop 类似,不支持修改

logger

查看logger信息,更新logger level

logger # 查看所有logger对象信息
logger -n [name] # 查看名为name的logger信息
logger -c [classloader] -n [name] -l ERROR # 修改名为name的logger级别为ERROR,需指定类加载器

sc

查看JVM已加载的类信息

sc -d org.apache.commons.lang.StringUtils # 查看StringUtils详细信息
sc -d org/apache/commons/lang/StringUtils # 查看StringUtils详细信息
sc -d *StringUtils # 查看StringUtils,根据*匹配
sc -d -f org.apache.commons.lang.StringUtils # 查看类及成员变量信息,f要配合d使用才有效

sm

查看已加载类的方法信息,用法和 sc 类似

sm java.lang.String # 查看String的所有方法
sm -d org.apache.commons.lang.StringUtils # 查看String方法详情
sm -d org/apache/commons/lang/StringUtils # 查看String方法详情
sm *StringUtils * # 查看String方法,根据*匹配

dump

dump 已加载类的 bytecode 到特定目录

dump java.lang.String # dump java.lang.String.class文件
dump java.lang.* # dump 批量dump
dump -d /tmp/output java.lang.String # dump到指定目录
dump org/apache/commons/lang/StringUtils # dump,支持目录格式
dump *StringUtils # dump,根据*匹配

jad

反编译指定已加载类的源码

jad java.lang.String # 反编译String类
jad java.lang.String toString # 反编译指定方法
jad --source-only java.lang.String # 反编绎时只显示源代码
jad -c 39eb305e org/apache/log4j/Logger # 反编译指定classloader

classloader

查看classloader的继承树,urls,类加载信息

classloader	# 列出所有classLoader
classloader -t # 树形结构列出所有classLoader
classloader -l # 统计每个classLoader加载类数量
classloader -c 327a647b # 查看具体的classLoader
classloader -a # 列出所有加载的类
classloader -c 659e0bfd --load demo.MathGame # 使用指定classLoader加载类

mc

编译.java文件生成.class

mc /tmp/Test.java	# 编译Test.java
mc -c 327a647b /tmp/Test.java # 使用 -c 指定classLoader
mc -d /tmp/output /tmp/ClassA.java /tmp/ClassB.java # 使用 -d 指定输出目录

redefine

加载外部的.class文件

redefine命令和jad/watch/trace/monitor/tt等命令会冲突。执行完redefine之后,如果再执行上面提到的命令,则会把redefine的字节码重置。 原因是jdk本身redefine和Retransform是不同的机制,同时使用两种机制来更新字节码,只有最后修改的会生效。

redefine /tmp/Test.class	# 加载类
redefine -c 327a647b /tmp/Test.class /tmp/Test\$Inner.class # 指定classLoader

通常结合 jad/mc 使用

  • jad命令反编译,然后可以用其它编译器,比如vim来修改源码
  • mc命令来内存编译修改过的代码
  • 用redefine命令加载新的字节码

redefine的限制

  • 不允许新增加 field/method
  • 正在跑的函数,没有退出不能生效

watch

方法执行数据观测

# 方法调用前观察,可以是非静态方法
watch -b org.apache.commons.lang.StringUtils isBlank params
# 在方法结束之后(正常返回和异常返回)观察
watch -f org.apache.commons.lang.StringUtils isBlank returnObj
# 指定输出结果的属性遍历深度,2
watch org.apache.commons.lang.StringUtils isBlank '{params, target, returnObj}' -x 2
# 耗时100ms时输出
watch *StringUtils isBlank params '#cost>100'
@RestController
public class UserController {
@GetMapping("/user/{id}")
public User getUser(@PathVariable Integer id) {
if (null == id) {
throw new IllegalArgumentException("id can not be null");
}
if (id < 1) {
throw new IllegalArgumentException("id must be greater than 1");
}
return new User(id, "zhangsan");
}
}

使用如下 watch 命令,然后访问 http://localhost:9090/user/10

watch com.soulballad.usage.arthasdemo.web.UserController getUser "{params,target,returnObj}" -x 2 -b -s -n 2

  • 参数里-n 2,表示只执行两次
  • 输出结果中,第一次输出的是方法调用前的观察结果,第二次输出的是方法返回后的表达式的结果
  • 结果的输出顺序和事件发生的先后顺序一致,和命令中 -s -b 的顺序无关

trace

方法内部调用路径,并输出方法路径上的每个节点上耗时

trace org.apache.commons.lang.StringUtils isBlank # 查看isBlank方法调用路径及耗时
trace *StringUtils isBlank # 使用*匹配
trace *StringUtils isBlank '#cost>100' # 过滤只输出耗时大于100ms的记录
# 正则表达式,支持多个路径记录
trace -E com.test.ClassA|org.test.ClassB method1|method2|method3
trace demo.MathGame run -n 5 # 只执行5次
trace demo.MathGame run --skipJDKMethod false # 不跳过jdk中方法,默认为true

stack

输出当前方法被调用的调用路径

支持条件过滤和 ognl 表达式

tt

方法执行数据的时空隧道,记录下指定方法每次调用的入参和返回信息,并能对这些不同的时间下调用进行观测

tt -t *StringUtils isEmpty # 记录isEmpty方法调用
tt -t *StringUtils isEmpty params[0].length==1 # 解决方法重载
tt -l # 查看所有记录
tt -i 1000 # 查询index为1000的记录详情
tt -i 1000 -p # 根据index重新触发调用
tt -i 1000 -p --replay-times 3 --replay-interval 3000 # 指定触发间隔和次数
tt --delete-all # 删除所有记录

ognl

执行ognl表达式

ognl '@java.lang.System@out.println("hello")' # 调用静态函数
ognl -x 2 '@Singleton@getInstance()' # 2层
ognl '@Demo@staticFiled' # 输出静态变量值
# 把java.home和java.runtime.name的系统属性放到一个集合中输出
ognl '#value1=@System@getProperty("java.home"), #value2=@System@getProperty("java.runtime.name"), {#value1, #value2}'
ognl -c 5d113a51 '@com.taobao.arthas.core.GlobalOptions@isDump' # 输出false

最新文章

  1. Android N开发 你需要知道的一切
  2. 如何利用tcpdump对mysql进行抓包操作
  3. 自学MVC看这里——全网最全ASP.NET MVC 教程汇总
  4. Oracle Minus关键字
  5. Mac 终端命令大全
  6. Freemarker 各种格式化
  7. Babelfish(二分查找,字符串的处理略有难度,用sscanf输入)
  8. 清除mac os svn密码命令行缓存
  9. SQLServer根据不同前缀生成多套流水号
  10. 微软职位内部推荐-Software Development Engineering II
  11. 七维互联(www.7wei.com)
  12. 树状数组HDU1166
  13. SQL笔记 [长期更新] (-2013.7)
  14. Windows环境自动获取AWR报告
  15. 简单的网页布局效果html5+CSS3
  16. 安装 macbook 双系统( OS X 和 Ubuntu )
  17. PHP 数据库 ODBC
  18. hdu 3681 Prison Break(状态压缩+bfs)
  19. TypeScript技巧集锦(陆续更新)
  20. Unity 本地坐标到世界坐标,世界坐标到本地坐标

热门文章

  1. PyTorch中在反向传播前为什么要手动将梯度清零?
  2. 二、Go语言开发环境安装与编写第一个Hello World
  3. Kubernetes笔记(一):十分钟部署一套K8s环境
  4. python 字符与数字如何转换
  5. spark2.4.5计算框架中各模块的常用实例
  6. 【mybatis annotation】数据层框架应用--Mybatis(二) 基于注解实现数据的CRUD
  7. 地点下来框的实现(php)
  8. opencv-9-图像噪声以及评估指标 PSNR 与SSIM
  9. 更加安全的密钥生成方法Diffie-Hellman
  10. 【手把手教你】win10 虚拟机 VMware Workstation Pro 15下安装Ubuntu 19.04