一、Arthas(阿尔萨斯) 能为你做什么?
Arthas
是Alibaba开源的Java诊断工具,深受开发者喜爱。
当你遇到以下类似问题而束手无策时,Arthas
可以帮助你解决:
- 这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?
- 我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?
- 遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?
- 线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!
- 是否有一个全局视角来查看系统的运行状况?
- 有什么办法可以监控到JVM的实时运行状态?
- 怎么快速定位应用的热点,生成火焰图?
二、快速安装
下载arthas-boot.jar
,然后用java -jar
的方式启动:
curl -O https://alibaba.github.io/arthas/arthas-boot.jar
// 运行命令之前,先运行一个java进程在内存中,不然会出现找不到java进程的错误
java -jar arthas-boot.jar
如果下载速度比较慢,可以使用aliyun的镜像:
java -jar arthas-boot.jar --repo-mirror aliyun --use-http
1、Windows下安装
1、在d:\下创建目录arthas,在windows命令窗口下,使用curl命令下载阿里服务器上的jar包,大小108k
2、使用java启动arthas-boot.jar,来安装arthas,大小约10M。
运行此命令会发现java进程,输入1按回车。则自动从远程主机上下载arthas到本地目录
3、查看安装好的目录
2、Linux下安装
1) 从Maven仓库下载全量包
https://maven.aliyun.com/repository/public/com/taobao/arthas/arthas-packaging/3.1.7/arthas-packaging-3.1.7-bin.zip
2)上传到linux服务器
3)使用以下命令解压到指定的arthas目录
unzip -d arthas arthas-packaging-3.1.7-bin.zip
4)启动 arthas-boot.jar
3、window下卸载 arthas
删除arthas安装目录下的 .arthas 和 logs/arthas logs/arthas-cache
4、linux下卸载 arthas
三、快速入门:attach一个进程
1、启动一个java进程
arthas 解压的包下面的 arthas-demo.jar
java -jar arthas-demo.jar
2、启动arthas
- 因为arthas-demo.jar进程打开了一个窗口,所以另开一个命令窗口执行arthas-boot.jar
- 选择要粘附的进程:arthas-demo.jar —》1
如果端口号被占用,也可以通过以下命令换成另一个端口号执行
java -jar arthas-boot.jar --telnet-port 9998 --http-port -1
四、基础命令
1、help
查看命令帮助信息
2、cat
打印文件内容,和linux里的cat命令类似
3、grep
匹配查找,和linux里的grep命令类似,但它只能用于管道命令
4、pwd
返回当前的工作目录,和linux命令类似
5、cls
清空当前屏幕区域
6、session
查看当前会话的信息
7、reset
重置增强类,将被 Arthas 增强过的类全部还原,Arthas 服务端关闭时会重置所有增强过的类
8、version
输出当前目标 Java 进程所加载的 Arthas 版本号
9、quit
退出当前 Arthas 客户端,其他 Arthas 客户端不受影响
10、stop
关闭 Arthas 服务端,所有 Arthas 客户端全部退出
11、keymap
Arthas快捷键列表及自定义快捷键
五、jvm相关命令
1、dashboard
显示当前系统的实时数据面板,按q或ctrl+c退出
数据说明
- ID: Java级别的线程ID,注意这个ID不能跟jstack中的nativeID一一对应
- NAME: 线程名
- GROUP: 线程组名
- PRIORITY: 线程优先级, 1~10之间的数字,越大表示优先级越高
- STATE: 线程的状态
- CPU%: 线程消耗的cpu占比,采样100ms,将所有线程在这100ms内的cpu使用量求和,再算出每个线程的cpu使用占比。
- TIME: 线程运行总时间,数据格式为
分:秒
- INTERRUPTED: 线程当前的中断位状态
- DAEMON: 是否是daemon线程
2、thread线程相关
查看当前 JVM 的线程堆栈信息
- thread -n 3:展示当前最忙的前3个线程并打印堆栈
- thread: 当没有参数时,显示所有线程的信息
- thread xxx:显示xxx线程的运行堆栈
- thread -b : 找出当前阻塞其他线程的线程
找出当前阻塞其他线程的线程,有时候我们发现应用卡住了, 通常是由于某个线程拿住了某个锁, 并且其他线程都在等待这把锁造成 的。 为了排查这类问题, arthas提供了thread -b, 一键找出那个罪魁祸首。
public class DeadLockTest {
private static final Object lock1 = new Object();
private static final Object lock2 = new Object();
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
synchronized (lock1) {
System.out.println("Thread 1 acquired lock1");
try {
Thread.sleep(100); // 让线程1休眠一段时间,让线程2有机会获取lock2
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread 1 waiting for lock2");
synchronized (lock2) {
System.out.println("Thread 1 acquired lock2");
}
}
});
Thread thread2 = new Thread(() -> {
synchronized (lock2) {
System.out.println("Thread 2 acquired lock2");
System.out.println("Thread 2 waiting for lock1");
synchronized (lock1) {
System.out.println("Thread 2 acquired lock1");
}
}
});
thread1.start();
thread2.start();
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Both threads completed execution");
}
}
- thread -i 1000 -n 3:指定采样时间间隔,每过1000毫秒采样,显示最占时间的3个线程
- thread --state WAITING: 查看处于等待状态的线程
3、jvm
查看当前 JVM 的信息
4、sysprop
查看和修改JVM的系统属性
- 查看所有属性:sysprop
- 查看单个属性,支持通过tab补全: sysprop java.version
- 修改单个属性:sysprop user.country CN
5、sysenv
查看当前JVM的环境属性( System Environment Variables )
- 查看所有环境变量:sysenv
- 查看单个环境变量:sysenv USER
6、vmoption
查看,更新VM诊断相关的参数
查看所有的选项
vmoption
查看指定的选项
vmoption PrintGCDetails
更新指定的选项
vmoption PrintGCDetails true
7、getstatic
通过getstatic命令可以方便的查看类的静态属性
语法:getstatic 类名 属性名
8、ognl
执行ognl表达式,这是从3.0.5版本新增的功能
六、class/classloader相关命令
1、sc
“Search-Class” 的简写,这个命令能搜索出所有已经加载到 JVM 中的Class 信息
2、sm
“Search-Method” 的简写,这个命令能搜索出所有已经加载了 Class 信息的方法信息。
3、jad
反编译指定已加载类的源码。
jad 命令将 JVM 中实际运行的 class 的 byte code 反编译成 java 代码,便于你理解业务逻辑;
反编绎时只显示源代码,默认情况下,反编译结果里会带有ClassLoader信息,通过–source-only选项,可以只打印源代码。方便和mc/redefine命令结合使用。
jad --source-only demo.MathGame
4、mc
Memory Compiler/内存编译器,编译 .java 文件生成 .class
在内存中编译Hello.java为Hello.class
mc /mysoft/arthas/Hello.java
可以通过-d命令指定输出目录
mc -d /mysoft/arthas /mysoft/arthas/Hello.java
5、redefine
加载外部的 .class 文件,redefine到JVM里
【案例】结合 jad/mc 命令使用
-
使用jad反编译demo.MathGame输出到/root/MathGame.java
jad --source-only demo.MathGame > /root/MathGame.java -
对/root/MathGame.java进行编辑
-
使用mc内存中对新的代码编译
mc /root/MathGame.java -d /root -
使用redefine命令加载新的字节码
redefine /root/demo/MathGame.class