阿里开源的Java 虚拟机诊断利器:Arthas(阿尔萨斯)入门

快速入门

1. 启动Demo

curl -O https://arthas.aliyun.com/arthas-demo.jar
java -jar arthas-demo.jar

arthas-demo是一个简单的程序,每隔一秒生成一个随机数,再执行质因数分解,并打印出分解结果。

arthas-demo源代码:查看

Arthas 命令初步使用,大概分为 5 类:

基础命令

  • help——查看命令帮助信息
  • cat——打印文件内容,和 linux 里的 cat 命令类似
  • pwd——返回当前的工作目录,和 linux 命令类似
  • cls——清空当前屏幕区域
  • session——查看当前会话的信息
  • reset——重置增强类,将被 Arthas 增强过的类全部还原,Arthas 服务端关闭时会重置所有增强过的类
  • version——输出当前目标 Java 进程所加载的 Arthas 版本号
  • history——打印命令历史
  • quit——退出当前 Arthas 客户端,其他 Arthas 客户端不受影响
  • shutdown——关闭 Arthas 服务端,所有 Arthas 客户端全部退出
  • keymap——Arthas快捷键列表及自定义快捷键

jvm相关

  • dashboard——当前系统的实时数据面板
  • thread——查看当前 JVM 的线程堆栈信息
  • jvm——查看当前 JVM 的信息
  • sysprop——查看和修改 JVM 的系统属性
  • sysenv——查看 JVM 的环境变量
  • getstatic——查看类的静态属性
  • New! ognl——执行 ognl 表达式
  • New! mbean——查看 Mbean 的信息

class/classloader相关

  • sc——查看 JVM 已加载的类信息
  • sm——查看已加载类的方法信息
  • jad——反编译指定已加载类的源码
  • mc——内存编绎器,内存编绎 .java 文件为 .class 文件
  • redefine——加载外部的 .class 文件,redefine 到 JVM 里
  • dump——dump 已加载类的 byte code 到特定目录
  • classloader——查看 classloader 的继承树,urls,类加载信息,使用 classloader 去 getResource

monitor/watch/trace 相关

请注意,这些命令,都通过字节码增强技术来实现的,会在指定类的方法中插入一些切面来实现数据统计和观测,因此在线上、预发使用时,请尽量明确需要观测的类、方法以及条件,诊断结束要执行 shutdown 或将增强过的类执行 reset 命令。

  • monitor——方法执行监控
  • watch——方法执行数据观测
  • trace——方法内部调用路径,并输出方法路径上的每个节点上耗时
  • stack——输出当前方法被调用的调用路径
  • tt——方法执行数据的时空隧道,记录下指定方法每次调用的入参和返回信息,并能对这些不同的时间下调用进行观测


2. 启动arthas

在命令行下面执行(使用和目标进程一致的用户启动,否则可能attach失败):


curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar
  • 执行该程序的用户需要和目标进程具有相同的权限。比如以admin用户来执行:sudo su admin && java -jar arthas-boot.jarsudo -u admin -EH java -jar arthas-boot.jar

  • 如果attach不上目标进程,可以查看~/logs/arthas/ 目录下的日志。

  • 如果下载速度比较慢,可以使用aliyun的镜像:java -jar arthas-boot.jar --repo-mirror aliyun --use-http

  • java -jar arthas-boot.jar -h 打印更多参数信息。

选择应用java进程:


$ $ java -jar arthas-boot.jar
* [1]: 35542
[2]: 71560 arthas-demo.jar

Demo进程是第2个,则输入2,再输入回车/enter。Arthas会attach到目标进程上,并输出日志:


[INFO] Try to attach process 71560
[INFO] Attach process 71560 success.
[INFO] arthas-client connect 127.0.0.1 3658
,---.  ,------. ,--------.,--.  ,--.  ,---.   ,---.
/  O  \ |  .--. ''--.  .--'|  '--'  | /  O  \ '   .-'
|  .-.  ||  '--'.'   |  |   |  .--.  ||  .-.  |`.  `-.
|  | |  ||  |\  \    |  |   |  |  |  ||  | |  |.-'    |
`--' `--'`--' '--'   `--'   `--'  `--'`--' `--'`-----'

wiki: https://arthas.aliyun.com/doc
version: 3.0.5.20181127201536
pid: 71560
time: 2018-11-28 19:16:24

$

3. 查看dashboard

输入dashboard,按回车/enter,会展示当前进程的信息,按ctrl+c可以中断执行。


$ dashboard
ID     NAME                   GROUP          PRIORI STATE  %CPU    TIME   INTERRU DAEMON
17     pool-2-thread-1        system         5      WAITIN 67      0:0    false   false
27     Timer-for-arthas-dashb system         10     RUNNAB 32      0:0    false   true
11     AsyncAppender-Worker-a system         9      WAITIN 0       0:0    false   true
9      Attach Listener        system         9      RUNNAB 0       0:0    false   true
3      Finalizer              system         8      WAITIN 0       0:0    false   true
2      Reference Handler      system         10     WAITIN 0       0:0    false   true
4      Signal Dispatcher      system         9      RUNNAB 0       0:0    false   true
26     as-command-execute-dae system         10     TIMED_ 0       0:0    false   true
13     job-timeout            system         9      TIMED_ 0       0:0    false   true
1      main                   main           5      TIMED_ 0       0:0    false   false
14     nioEventLoopGroup-2-1  system         10     RUNNAB 0       0:0    false   false
18     nioEventLoopGroup-2-2  system         10     RUNNAB 0       0:0    false   false
23     nioEventLoopGroup-2-3  system         10     RUNNAB 0       0:0    false   false
15     nioEventLoopGroup-3-1  system         10     RUNNAB 0       0:0    false   false
Memory             used   total max    usage GC
heap               32M    155M  1820M  1.77% gc.ps_scavenge.count  4
ps_eden_space      14M    65M   672M   2.21% gc.ps_scavenge.time(m 166
ps_survivor_space  4M     5M    5M           s)
ps_old_gen         12M    85M   1365M  0.91% gc.ps_marksweep.count 0
nonheap            20M    23M   -1           gc.ps_marksweep.time( 0
code_cache         3M     5M    240M   1.32% ms)
Runtime
os.name                Mac OS X
os.version             10.13.4
java.version           1.8.0_162
java.home              /Library/Java/JavaVir
tualMachines/jdk1.8.0
_162.jdk/Contents/Hom
e/jre

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

thread 1会打印线程ID 1的栈,通常是main函数的线程。


$ thread 1 | grep 'main('
at demo.MathGame.main(MathGame.java:17)

5. 通过jad来反编译Main Class


$ jad demo.MathGame

ClassLoader:
+-sun.misc.Launcher$AppClassLoader@3d4eac69
+-sun.misc.Launcher$ExtClassLoader@66350f69

Location:
/tmp/arthas-demo.jar

/*
 * Decompiled with CFR 0_132.
 */
package demo;
import java.io.PrintStream;

import java.util.ArrayList;

import java.util.Iterator;

import java.util.List;

import java.util.Random;

import java.util.concurrent.TimeUnit;


public class MathGame {

private static Random random = new Random();

private int illegalArgumentCount = 0;


public static void main(String[] args) throws InterruptedException {

MathGame game = new MathGame();

do {

game.run();

TimeUnit.SECONDS.sleep(1L);

} while (true);

}


public void run() throws InterruptedException {

try {

int number = random.nextInt();

List<Integer> primeFactors = this.primeFactors(number);

MathGame.print(number, primeFactors);

}

catch (Exception e) {

System.out.println(String.format("illegalArgumentCount:%3d, ", this.illegalArgumentCount) + e.getMessage());

}

}


public static void print(int number, List<Integer> primeFactors) {

StringBuffer sb = new StringBuffer("" + number + "=");

Iterator<Integer> iterator = primeFactors.iterator();

while (iterator.hasNext()) {

int factor = iterator.next();

sb.append(factor).append('*');

}

if (sb.charAt(sb.length() - 1) == '*') {

sb.deleteCharAt(sb.length() - 1);

}

System.out.println(sb);

}


public List<Integer> primeFactors(int number) {

if (number < 2) {

++this.illegalArgumentCount;

throw new IllegalArgumentException("number is: " + number + ", need >= 2");

}

ArrayList<Integer> result = new ArrayList<Integer>();

int i = 2;

while (i <= number) {

if (number % i == 0) {

result.add(i);

number /= i;

i = 2;

continue;

}

++i;

}

return result;

}

}
Affect(row-cnt:1) cost in 970 ms.

6. watch

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


$ watch demo.MathGame primeFactors returnObj
Press Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 107 ms.
ts=2018-11-28 19:22:30; [cost=1.715367ms] result=null
展开阅读全文

本文系作者在时代Java发表,未经许可,不得转载。

如有侵权,请联系nowjava@qq.com删除。

编辑于

关注时代Java

关注时代Java