Arthas使用与进阶

Arthas (阿尔萨斯) 能为你做什么? Arthas使用与进阶

Arthas 是Alibaba开源的Java诊断工具,深受开发者喜爱。 当你遇到以下类似问题而束手无策时, Arthas 可以帮助你解决: 1. 这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception? 2. 我改的代码为什么没有执行到?难道是我没 commit?分支搞错了? 3. 遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗? 4. 线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现! 5. 是否有一个全局视角来查看系统的运行状况? 6. 有什么办法可以监控到JVM的实时运行状态? 7. 怎么快速定位应用的热点,生成火焰图? Arthas 支持JDK 6+,支持Linux/Mac/Winodws,采用命令行交互模式,同时提供丰富的 Tab 自动补 全功能,进一步方便进行问题的定位和诊断。 下载 arthas - boot.jar ,然后用 java - jar 的方式启动: 命令
curl -O https://alibaba.github.io/arthas/arthas-boot.jar 
java -jar arthas-boot.jar
如果下载速度比较慢,可以使用aliyun的镜像:
java -jar arthas-boot.jar --repo-mirror aliyun --use-http 1
Windows 下安装 1. 在c:\下创建目录arthas,在windows命令窗口下,使用curl命令下载阿里服务器上的jar包,大小 108k Arthas使用与进阶 2. 使用java启动arthas-boot.jar,来安装arthas,大小约10M。运行此命令会发现java进程,输入1 按回车。则自动从远程主机上下载arthas到本地目录 Arthas使用与进阶

 3. 查看安装好的目录

C:\Users\Administrator\.arthas\lib\3.1.7\arthas\
Arthas使用与进阶

Ma ven 如果下载速度比较慢,可以尝试用 阿里云的镜像仓库

 步骤

1. 比如要下载 3.1.7 版本,下载的url是: https://maven.aliyun.com/repository/public/com/taobao/arthas/arthas-packaging/3.1.7/arthas -packaging-3.1.7-bin.zip Arthas使用与进阶

 2. 解压后,在文件夹里有 arthas-boot.jar ,直接用 java -jar 的方式启动:

java -jar arthas-boot.jar

注:如果是Linux,可以使用以下命令解压到指定的arthas目录

unzip -d arthas arthas-packaging-3.1.7-bin.zip

Arthas使用与进阶

 卸载

Arthas使用与进阶

 

需求 1. 执行一个jar包 2. 通过arthas来粘附,并且进行几种常用的操作 3. 通过一个案例快速入门

步骤

1. 准备代码 以下是一个简单的Java程序,每隔一秒生成一个随机数,再执行质因数分解,并打印出分解结果。代码 的内容不用理会这不是现在关注的点。
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 {//随机生成1万以内的整数
            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("numberis:" + 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;
    }
}

2. 启动Demo

命令

下载已经打包好的arthas-demo.jar 
curl -O https://alibaba.github.io/arthas/arthas-demo.jar 
在命令行下执行 
java -jar arthas-demo.jar

效果

Arthas使用与进阶

 3. 启动arthas

1. 因为arthas-demo.jar进程打开了一个窗口,所以另开一个命令窗口执行arthas-boot.jar 2. 选择要粘附的进程:arthas-demo.jar

Arthas使用与进阶

3. 如果粘附成功,在arthas-demo.jar那个窗口中会出现日志记录的信息,记录在 c:\Users\Administrator\logs目录下

Arthas使用与进阶

 4. 如果端口号被占用,也可以通过以下命令换成另一个端口号执行

java -jar arthas-boot.jar --telnet-port 9998 --http-port -1
4. 通过浏览器连接 arthas Arthas目前支持Web Console,用户在attach成功之后,可以直接访问: http://127.0.0.1:3658/ 。 可以填入IP,远程连接其它机器上的arthas。 Arthas使用与进阶 默认情况下,arthas只listen 127.0.0.1,所以如果想从远程连接,则可以使用 -- target - ip 参数指定 listen的IP 5. dashboard 仪表板 输入dashboard(仪表板),按 回车 /enter ,会展示当前进程的信息,按 ctrl+c 可以中断执行。 注:输入前面部分字母,按tab可以自动补全命令 1. 第一部分是显示JVM中运行的所有线程:所在线程组,优先级,线程的状态,CPU的占用率,是 否是后台进程等 2. 第二部分显示的JVM内存的使用情况 3. 第三部分是操作系统的一些信息和Java版本号 Arthas使用与进阶

 6. 通过thread命令来获取到 arthas-demo 进程的Main Class

获取到arthas-demo进程的Main Class thread 1 会打印线程ID 1的栈,通常是main函数的线程。 Arthas使用与进阶

 7. 通过jad来反编译Main Class

jad demo.MathGame
Arthas使用与进阶

 8. watch

通过watch命令来查看 demo.MathGame#primeFactors 函数的返回值:
$ watch demo.MathGame primeFactors returnObj

Arthas使用与进阶

 9. 退出arthas

如果只是退出当前的连接,可以用 quit 或者 exit 命令。Attach到目标进程上的arthas还会继续运行, 端口会保持开放,下次连接时可以直接连接上。 如果想完全退出arthas,可以执行 stop 命令。 小结 1. 如何启动arthas? 2. 说说以下命令的作用 Arthas使用与进阶

help 作用 查看命令帮助信息 效果 Arthas使用与进阶cat 作用 打印文件内容,和linux里的cat命令类似 注:汉字有乱码的问题 如果没有写路径,则显示当前目录下的文件 效果 Arthas使用与进阶

grep 作用 匹配查找,和linux里的grep命令类似,但它只能用于管道命令 语法 Arthas使用与进阶 举例
只显示包含java字符串的行系统属性 
sysprop | grep java
Arthas使用与进阶

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

Arthas使用与进阶

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

Arthas使用与进阶

使用正则表达式,显示包含2个o字符的线程信息 
thread | grep -e "o+"
pwd 作用 返回当前的工作目录,和linux命令类似 效果 Arthas使用与进阶

cls 作用 清空当前屏幕区域 session 作用 查看当前会话的信息 效果 Arthas使用与进阶

reset

作用 重置增强类,将被 Arthas 增强过的类全部还原,Arthas 服务端关闭时会重置所有增强过的类 语法
还原指定类 reset Test 还原所有以 List 结尾的类 reset *List 还原所有的类 reset
效果 Arthas使用与进阶

version 作用 输出当前目标 Java 进程所加载的 Arthas 版本号 效果 Arthas使用与进阶history 作用 打印命令历史 效果 Arthas使用与进阶

quit 作用 退出当前 Arthas 客户端,其他 Arthas 客户端不受影响 stop 作用 关闭 Arthas 服务端,所有 Arthas 客户端全部退出 效果

 Arthas使用与进阶

keymap 作用 Arthas快捷键列表及自定义快捷键 效果 Arthas使用与进阶

Arthas Arthas使用与进阶
  • 任何时候 tab 键,会根据当前的输入给出提示
  • 命令后敲 - 或 -- ,然后按 tab 键,可以展示出此命令具体的选项
后台异步命令相关快捷键
  • ctrl + c: 终止当前命令
  • ctrl + z: 挂起当前命令,后续可以 bg/fg 重新支持此命令,或 kill 掉
  • ctrl + a: 回到行首
  • ctrl + e: 回到行尾
jvm dashboard 作用 显示当前系统的实时数据面板,按q或ctrl+c退出 效果 Arthas使用与进阶thread 作用 查看当前 JVM 的线程堆栈信息 参数说明

 Arthas使用与进阶

 举例

展示当前最忙的前3个线程并打印堆栈 
thread -n 3

Arthas使用与进阶

当没有参数时,显示所有线程的信息 
thread 12 显示1号线程的运行堆栈 
thread 1 12

Arthas使用与进阶

找出当前阻塞其他线程的线程,有时候我们发现应用卡住了, 通常是由于某个线程拿住了某个锁,
 并且 其他线程都在等待这把锁造成的。 为了排查这类问题, 
arthas提供了thread -b, 一键找出那个罪魁 祸首。 

thread -b

 Arthas使用与进阶

指定采样时间间隔,每过1000毫秒采样,显示最占时间的3个线程 
thread -i 1000 -n 3

Arthas使用与进阶

查看处于等待状态的线程 
thread --state WAITING

Arthas使用与进阶

jvm 作用 查看当前 JVM 的信息 效果

Arthas使用与进阶

 文件描述符相关

  • MAX-FILE-DESCRIPTOR-COUNT:JVM进程最大可以打开的文件描述符数
  • OPEN-FILE-DESCRIPTOR-COUNT:JVM当前打开的文件描述符数
sysprop 作用 查看和修改JVM的系统属性 举例
查看所有属性 
sysprop 
查看单个属性,支持通过tab补全 
sysprop java.version

Arthas使用与进阶

 修改单个属性

sysprop user.country user.country=US sysprop user.country CN Successfully changed the system property. user.country=CN

Arthas使用与进阶

sysenv 作用 查看当前JVM的环境属性( System Environment Variables ) 举例
查看所有环境变量 
sysenv 
查看单个环境变量 
sysenv USER
效果 Arthas使用与进阶

 

vmoption 作用 查看,更新VM诊断相关的参数 举例 Arthas使用与进阶

 

更新指定的选项 
vmoption PrintGCDetails true
Arthas使用与进阶

 

getstatic 作用 通过getstatic命令可以方便的查看类的静态属性 语法
getstatic 类名 属性名
举例
显示demo.MathGame类中静态属性random 
getstatic demo.MathGame random

Arthas使用与进阶

 

ognl 作用 执行ognl表达式,这是从3.0.5版本新增的功能 参数说明 Arthas使用与进阶

 

举例
调用静态函数 
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}'
效果 Arthas使用与进阶class/classload er sc 作用 查看JVM已加载的类信息,“Search-Class” 的简写,这个命令能搜索出所有已经加载到 JVM 中的 Class 信息 sc 默认开启了子类匹配功能,也就是说所有当前类的子类也会被搜索出来,想要精确的匹配,请打开 options disable - sub - class true 开关

 参数说明

Arthas使用与进阶

 举例

模糊搜索,demo包下所有的类 
sc demo.* 
打印类的详细信息 
sc -d demo.MathGame

Arthas使用与进阶

 

打印出类的Field信息 
sc -df demo.MathGame

Arthas使用与进阶

sm 作用 查看已加载类的方法信息 “Search-Method” 的简写,这个命令能搜索出所有已经加载了 Class 信息的方法信息。
sm 命令只能看到由当前类所声明 (declaring) 的方法,父类则无法看到。
参数说明 Arthas使用与进阶

 举例

显示String类加载的方法
sm java.lang.String

Arthas使用与进阶

 

显示String中的toString方法详细信息
sm -d java.lang.String toString

Arthas使用与进阶

 

jad 作用
反编译指定已加载类的源码 jad 命令将 JVM 中实际运行的 class 的 byte code 反编译成 java 代码,便于你理解业务逻辑; 在 Arthas Console 上,反编译出来的源码是带语法高亮的,阅读更方便 当然,反编译出来的 java 代码可能会存在语法错误,但不影响你进行阅读理解
参数说明

Arthas使用与进阶

 举例

编译java.lang.String 
jad java.lang.String
反编绎时只显示源代码,默认情况下,反编译结果里会带有ClassLoader信息,通过--source-only选 项,可以只打印源代码。方便和mc/redefine命令结合使用。 
jad --source-only demo.MathGame

Arthas使用与进阶

 反编译指定的函数

jad demo.MathGame main

Arthas使用与进阶

 

mc 作用 Memory Compiler/内存编译器,编译 .java 文件生成 .class 举例
在内存中编译 Hello.java 为 Hello.class mc /root/Hello.java 可以通过 -d 命令指定输出目录 mc -d /root/bbb /root/Hello.java
效果

Arthas使用与进阶

 

redefifine 作用 加载外部的 .class 文件,redefine到JVM里
注意, redefine后的原来的类不能恢复,redefine有可能失败(比如增加了新的field),参考 jdk本身的文档。 reset 命令对 redefine 的类无效。如果想重置,需要 redefine 原始的字节码。 redefine 命令和 jad / watch / trace / monitor / tt 等命令会冲突。执行完 redefine 之后,如果 再执行上面提到的命令,则会把 redefine 的字节码重置。
redefine 的限制 不允许新增加field/method 正在跑的函数,没有退出不能生效,比如下面新增加的 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("in loop");
        }
    }

    public void run() throws InterruptedException {
        // 这个生效,因为run()函数每次都可以完整结束 
        System.out.println("call 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输出到/root/MathGame.java 
jad --source-only demo.MathGame > /root/MathGame.java

2.按上面的代码编辑完毕以后,使用mc内存中对新的代码编译 
mc /root/MathGame.java -d /root

3.使用redefine命令加载新的字节码 
redefine /root/demo/MathGame.class
结果

Arthas使用与进阶

 

dump 作用 将已加载类的字节码文件保存到特定目录:logs/arthas/classdump/ 参数 Arthas使用与进阶

 Arthas使用与进阶

 

classloader 作用 1. classloader 命令将 JVM 中所有的classloader的信息统计出来,并可以展示继承树,urls等。 2. 可以让指定的classloader去getResources,打印出所有查找到的resources的url。对于 ResourceNotFoundException 异常比较有用。 参数说明 Arthas使用与进阶

 Arthas使用与进阶

 Arthas使用与进阶

 

monitor/watch/trace monitor 作用
方法执行监控对匹配 class - pattern / method - pattern 的类、方法的调用进行监控。 monitor 命令是一个非实时返回命令,实时返回命令是输入之后立即返回,而非实时返回的命 令,则是不断的等待目标 Java 进程返回信息,直到用户输入 Ctrl+C 为止。
参数说明 方法拥有一个命名参数 [c:] ,意思是统计周期(cycle of output),拥有一个整型的参数值 Arthas使用与进阶

 

过5秒统计一次,统计类demo.MathGame中primeFactors方法 
monitor -c 5 demo.MathGame primeFactors
Arthas使用与进阶

 

watch 作用
方法执行数据观测,让你能方便的观察到指定方法的调用情况. 能观察到的范围为: 返回值 、 抛出异常 、 入参 ,通过编写OGNL 表达式进行对应变量的查看。
参数说明 watch 的参数比较多,主要是因为它能在 4 个不同的场景观察对象 Arthas使用与进阶

 

Arthas使用与进阶

 

观察方法入参,对比前一个例子,返回值为空(事件点为方法执行前,因此获取不到返回值)
 watch demo.MathGame primeFactors "{params,returnObj}" -x 2 -b
Arthas使用与进阶

 同时观察方法调用前和方法返回后,参数里-n 2,表示只执行两次。

这里输出结果中,第一次输出的是方法调用前的观察表达式的结果,第二次输出的是方法返回后的表达式 的结果 params 表示参数, target 表示执行方法的对象, returnObject 表示返回值 watch demo.MathGame primeFactors "{params,target,returnObj}" -x 2 -b -s -n 2
Arthas使用与进阶

Arthas使用与进阶 

Arthas使用与进阶 

 

trace 作用
方法内部调用路径,并输出方法路径上的每个节点上耗时 trace 命令能主动搜索 class - pattern / method - pattern 对应的方法调用路径,渲染和统计整 个调用链路上的所有性能开销和追踪调用链路。 观察表达式的构成主要由ognl 表达式组成,所以你可以这样写 "{params,returnObj}" ,只要是 一个合法的 ognl 表达式,都能被正常支持。 很多时候我们只想看到某个方法的rt大于某个时间之后的trace结果,现在Arthas可以按照方法执 行的耗时来进行过滤了,例如 trace *StringUtils isBlank '#cost>100' 表示当执行时间超过 100ms的时候,才会输出trace的结果。 watch/stack/trace这个三个命令都支持 #cost
Arthas使用与进阶

 Arthas使用与进阶

 stack

作用
输出当前方法被调用的调用路径 很多时候我们都知道一个方法被执行,但这个方法被执行的路径非常多,或者你根本就不知道这 个方法是从那里被执行了,此时你需要的是 stack 命令。
参数说明 Arthas使用与进阶

 

获取primeFactors的调用路径 
stack demo.MathGame primeFactors
Arthas使用与进阶

 

条件表达式来过滤,第0个参数的值小于0,-n表示获取2次 
stack demo.MathGame primeFactors 'params[0]<0' -n 2
Arthas使用与进阶

 

Arthas使用与进阶

 

上一篇:Arthas实践


下一篇:java arthas