Arthas(阿尔萨斯)能为你做什么?

Arthas是Alibaba开源的Java诊断工具,深受开发者喜爱。
Arthas可以帮助你解决:
这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception? 我改的代码为什么没有执行到?难道是我没 commit?分支搞错了? 遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗? 线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现! 是否有一个全局视角来查看系统的运行状况? 有什么办法可以监控到JVM的实时运行状态? 怎么快速定位应用的热点,生成火焰图? 怎样直接从JVM内查找某个类的实例?
运行环境要求
Arthas支持JDK 6+,支持Linux/Mac/Windows,采用命令行交互模式,同时提供丰富的
Tab自动补全功能,进一步方便进行问题的定位和诊断。
快速安装
arthas-boot,下载
arthas-boot.jar,然后用
java -jar的方式启动:
curl -O <https://alibaba.github.io/arthas/arthas-boot.jar> java -jar arthas-boot.jar
java -jar arthas-boot.jar -h
aliyun的镜像:
java -jar arthas-boot.jar --repo-mirror aliyun --use-http
Windows 下安装



C:\\Users\\HUAWEI\\.arthas\\lib\\3.5.4\\arthas

小结
下载 arthas-boot.jar
包执行 arthas-boo.jar
包,前提是必须要有java
进程在运行。第一次执行这个jar
包,会自动从服务器上下载arthas
,大小是11
M
从Maven仓库下载全量包
步骤
3.5.4版本,下载的url是:
https://archiva-maven-storage-prod.oss-cn-beijing.aliyuncs.com/repository/jcenter/com/taobao/arthas/arthas-packaging/3.5.4/arthas-packaging-3.5.4-bin.zip%3B?Expires=1637823771&OSSAccessKeyId=LTAIfU51SusnnfCC&Signature=CAlIjIvMl4kh09oMtff%2FBgxyG2U%3D
arthas-boot.jar,直接用
java -jar的方式启动:
java -jar arthas-boot.jar
unzip -d /root/app/arthas arthas-packaging-3.5.4-bin.zip

小结
在Linux下在线安装的方式与在Windows下的安装相同 如果要使用离线的安装方式,先下载完成的zip到本地,再解压到任意的目录即可
卸载
在 Linux 平台
rm -rf ~/.arthas/rm -rf ~/logs/arthas
Windows平台
.arthas和
logs/arthas目录
快速入门:attach一个进程
目标:通过案例快速入门
执行一个jar包 通过arthas来attach粘附
步骤
1.下载以及Demo
下载已经打包好的arthas-demo.jar
curl -O <https://alibaba.github.io/arthas/arthas-demo.jar>
在命令行下执行
java -jar arthas-demo.jar

2. 启动 arthas

[ERROR] The telnet port 3658 is used by process 10472 instead of target process 284, you will connect to an unexpected process.[ERROR] 1. Try to restart arthas-boot, select process 10472, shutdown it first with running the 'stop' command.[ERROR] 2. Or try to stop the existing arthas instance: java -jar arthas-client.jar 127.0.0.1 3658 -c "stop"[ERROR] 3. Or try to use different telnet port, for example: java -jar arthas-boot.jar --telnet-port 9998 --http-port -1
java -jar arthas-boot.jar --telnet-port 9998 --http-port -1

3. 通过浏览器连接arthas

--target-ip参数指定listen的 IP
4. 查看 arthas-demo.jar 的代码
package demo;import java.util.ArrayList;import java.util.List;import java.util.Random;import java.util.concurrent.TimeUnit;public class MathGame { private static Random random = new Random(); //用于统计生成的不合法变量的个数 public int illegalArgumentCount = 0; public static void main(String[] args) throws InterruptedException { MathGame game = new MathGame(); //死循环,每过1秒调用1次下面的方法(不是开启一个线程) while (true) { game.run(); TimeUnit.SECONDS.sleep(1); } } //分解质因数 public void run() throws InterruptedException { try { //随机生成一个整数,有可能正,有可能负 int number = random.nextInt()/10000; //调用方法进行质因数分解 List<Integer> primeFactors = primeFactors(number); //打印结果 print(number, primeFactors); } catch (Exception e) { System.out.println(String.format("illegalArgumentCount:%3d, ", illegalArgumentCount) + e.getMessage()); } } //打印质因数分解的结果 public static void print(int number, List<Integer> primeFactors) { StringBuffer sb = new StringBuffer(number + "="); for (int factor : primeFactors) { sb.append(factor).append('*'); } if (sb.charAt(sb.length() - 1) == '*') { sb.deleteCharAt(sb.length() - 1); } System.out.println(sb); } //计算number的质因数分解 public List<Integer> primeFactors(int number) { //如果小于2,则抛出异常,并且计数加1 if (number < 2) { illegalArgumentCount++; throw new IllegalArgumentException("number is: " + number + ", need >= 2"); } //用于保存每个质数 List<Integer> result = new ArrayList<Integer>(); //分解过程,从2开始看能不能整除 int i = 2; while (i <= number) { //如果i大于number就退出循环 //能整除,则i为一个因数,number为整除的结果再继续从2开始除 if (number % i == 0) { result.add(i); number = number / i; i = 2; } else { i++; //否则i++ } } return result; }}
小结
启动被诊断进程 启动 arthas-boot.jar,粘贴上面的进程 不但可以通过命令行的方式来操作 arthas 也可以通过浏览器来访问 arthas
快速入门:常用命令接触
目标
dashboard仪表板 通过thread命令来获取到 arthas-demo
进程的Main Class通过jad来反编译Main Class watch
命令介绍
1. dashboard仪表板
回车/enter,会展示当前进程的信息,按
ctrl+c可以中断执行。
第一部分是显示JVM中运行的所有线程:所在线程组,优先级,线程的状态,CPU的占用率,是否是后台进程等 第二部分显示的JVM内存的使用情况 第三部分是操作系统的一些信息和 Java
版本号

2. 通过thread命令来获取到arthas-demo
进程的Main Class
thread 14会打印线程 ID 14的栈。如果是
thread 1会打印线程ID 1的栈,通常是main函数的线程。

thread 1示例图

jad demo.MathGame

4. watch监视
demo.MathGame#primeFactors函数的返回值:
watch demo.MathGame primeFactors returnObj

5. 退出arthas
quit或者
exit命令。Attach到目标进程上的arthas还会继续运行,端口会保持开放,下次连接时可以直接连接上。
stop命令。
小结
如何启动arthas? java -jar arthas-boot.jar说说以下命令的作用
| 命令 | 功能 |
基础命令之一
目标
help cat grep pwd cls
help
作用
效果

cat
效果

grep
作用
语法
| 参数列表 | 作用 |
只显示包含java字符串的行系统属性
sysprop | grep java

显示包含java字符串的行和行号的系统属性
sysprop | grep java -n

显示包含system字符串的10行信息
thread | grep system -m 10

thread | grep -e "o+"
pwd
作用
效果

cls
作用
基础命令之二
目标
session reset version quit stop keymap
session
作用
效果

reset
作用
语法
还原指定类reset Test还原所有以List结尾的类reset *List还原所有的类reset
效果

作用
效果

作用
效果

作用
stop
作用
效果

作用
效果

| 快捷键说明 | 命令说明 |
任何时候 tab
键,会根据当前的输入给出提示命令后敲 `` 或 -
,然后按tab
键,可以展示出此命令具体的选项
后台异步命令相关快捷键
ctrl + c: 终止当前命令 ctrl + z: 挂起当前命令,后续可以 bg/fg 重新支持此命令,或 kill 掉 ctrl + a: 回到行首 ctrl + e: 回到行尾
小结
| 命令 | 说明 |
jvm相关命令之一
目标
dashboard 仪表板 thread 线程相关 jvm 虚拟机相关 sysprop 系统属性相关
dashboard
作用
效果

ID: Java级别的线程ID,注意这个ID不能跟jstack中的nativeID一一对应 NAME: 线程名 GROUP: 线程组名 PRIORITY: 线程优先级, 1~10之间的数字,越大表示优先级越高 STATE: 线程的状态 CPU%: 线程消耗的cpu占比,采样100ms,将所有线程在这100ms内的cpu使用量求和,再算出每个线程的cpu使用占比。 TIME: 线程运行总时间,数据格式为 分:秒INTERRUPTED: 线程当前的中断位状态 DAEMON: 是否是daemon线程
thread线程相关
作用
参数说明
| 参数名称 | 参数说明 |
3个线程并打印堆栈,
thread -n 3
thread;当显示1号线程的运行堆栈,
thread 1
arthas提供了
thread -b, 一键找出那个罪魁祸首。
thread -b
1000毫秒采样,显示最占时间的
3个线程
thread -i 1000 -n 3
thread --state WAITING
jvm
作用
效果

THREAD相关
COUNT: JVM当前活跃的线程数 DAEMON-COUNT: JVM当前活跃的守护线程数 PEAK-COUNT: 从JVM启动开始曾经活着的最大线程数 STARTED-COUNT: 从JVM启动开始总共启动过的线程次数 DEADLOCK-COUNT: JVM当前死锁的线程数
文件描述符相关
MAX-FILE-DESCRIPTOR-COUNT:JVM进程最大可以打开的文件描述符数 OPEN-FILE-DESCRIPTOR-COUNT:JVM当前打开的文件描述符数
sysprop
作用
举例
查看所有属性
sysprop
查看单个属性,支持通过tab补全
sysprop java.version

修改单个属性
sysprop user.countryuser.country=USsysprop user.country CNSuccessfully changed the system property.user.country=CN

| jvm相关命令 | 说明 |
jvm相关命令之二
目标
sysenv vmoption getstatic ognl
sysenv
作用
System Environment Variables)
举例
查看所有环境变量
sysenv
查看单个环境变量
sysenv USER
效果

vmoption
作用
举例
查看所有的选项
vmoption
查看指定的选项
vmoption HeapDumpAfterFullGC

vmoption HeapDumpAfterFullGC true

getstatic
作用
语法
getstatic 类名 属性名
举例
显示demo.MathGame类中静态属性random
getstatic demo.MathGame random

ognl
作用
OGNL语法
http://commons.apache.org/proper/commons-ognl/language-guide.html

| 参数说明 | 参数名称 |
调用静态函数
ognl '@java.lang.System@out.println("hello")'
获取静态类的静态字段
ognl '@demo.MathGame@random'
执行多行表达式,赋值给临时变量,返回一个List
ognl '#value1=@System@getProperty("java.home"), #value2=@System@getProperty("java.runtime.name"), {#value1, #value2}'

| jvm相关命令 | 说明 |
class/classloader相关命令之一
目标
sc: Search Class sm: Search Method
sc
作用
options disable-sub-class true开关
参数说明
| 参数名称 | 参数说明 |
举例
模糊搜索,demo包下所有的类
sc demo.*
打印类的详细信息
sc -d demo.MathGame

Field 信息
sc -df demo.MathGame

sm
作用
sm命令只能看到由当前类所声明 (declaring) 的方法,父类则无法看到。
参数说明
| 参数名称 | 参数说明 |
举例
String类加载的方法,
sm java.lang.String
String中的
toString方法详细信息,
sm -d java.lang.String toString
小结
| 与类相关的命令 | 说明 |
class/classloader相关命令之二
目标
jad 把字节码文件反编译成源代码 mc 在内存中把源代码编译成字节码文件 redefine 把新生成的字节码文件在内存中执行
jad
作用
jad
命令将 JVM 中实际运行的 class 的 byte code 反编译成 java 代码,便于你理解业务逻辑;在 Arthas Console 上,反编译出来的源码是带语法高亮的,阅读更方便; 当然,反编译出来的 java 代码可能会存在语法错误,但不影响你进行阅读理解;
参数说明
| 参数名称 | 参数说明 |
举例
jad java.lang.Stringjad --source-only java.lang.Object
jad demo.MathGame main
mc
作用
.java文件生成
.class举例
在内存中编译Hello.java为helloworld.class
mc /data/helloworld.java
可以通过-d命令指定输出目录
mc -d /data/output /data/helloworld.java
效果

redefine
作用
.class文件,
redefine到
JVM里
注意, redefine后的原来的类不能恢复,redefine有可能失败(比如增加了新的field)。
reset命令对redefine的类无效。如果想重置,需要redefine原始的字节码。
redefine命令和jad/watch/trace/monitor/tt等命令会冲突。执行完redefine之后,如果再执行上面提到的命令,则会把redefine的字节码重置。
redefine的限制
不允许新增加field/method 正在跑的函数,没有退出不能生效,比如下面main()、run()方法中新增加的 System.out.println
,只有run()
函数里的会生效
public class MathGame { public static void main(String[] args) throws InterruptedException { MathGame game = new MathGame(); while (true) { game.run(); TimeUnit.SECONDS.sleep(1); // 这个不生效,因为代码一直跑在 while里 System.out.println("在 main 函数中添加"); } } public void run() throws InterruptedException { // 这个生效,因为run()函数每次都可以完整结束 System.out.println("在 run 函数中添加"); try { int number = random.nextInt(); List<Integer> primeFactors = primeFactors(number); print(number, primeFactors); } catch (Exception e) { System.out.println(String.format("illegalArgumentCount:%3d, ", illegalArgumentCount) + e.getMessage()); } } }
案例:结合 jad/mc 命令使用
步骤
1. 使用jad反编译demo.MathGame输出到/data/MathGame.javajad --source-only demo.MathGame > /data/MathGame.java2.按上面的代码编辑完毕以后,使用mc内存中对新的代码编译mc /data/MathGame.java -d /data3.使用redefine命令加载新的字节码redefine /data/demo/MathGame.class
结果


从上面可以得出,我们在 main() 方法新增的内容并没有生效,在 run() 方法新增的内容生效了。小结
| 类相关的命令 | 说明 |
学习总结
安装arthas的方法 既可以安装在windows下也可以安装在Linux curl -O <https://alibaba.github.io/arthas/arthas-boot.jar>
java -jar arthas-boot.jar离线安装 将从maven仓库中下载的zip包直接解压就可以使用 卸载方式 直接删除2个文件夹:.arthas和logs 在线安装 基础命令
| help | 显示所有arthas命令,每个命令都可以使用-h的参数,显示它的参数信息 |
| jvm相关命令 | 说明 |
| 类,类加载相关的命令 | 说明 |
参考
https://arthas.aliyun.com/doc/index.html
文章转载自Just do DT,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




