Alibaba Java诊断工具Arthas简单介绍 :
当你遇到以下类似问题而束手无策时,Arthas可以帮助你解决:
1.这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?
2.我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?
3.遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?
4.线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!
5.是否有一个全局视角来查看系统的运行状况?
6.有什么办法可以监控到JVM的实时运行状态?
Arthas支持JDK 6+,支持Linux/Mac/Windows,采用命令行交互模式,同时提供丰富的 Tab 自动补全功能,进一步方便进行问题的定位和诊断。
一、快速安装
这里我们使用官网推荐的arthas-boot
下载arthas-boot.jar,然后用java -jar的方式启动:
1 wget https://alibaba.github.io/arthas/arthas-boot.jar 2 java -jar arthas-boot.jar
打印帮助信息:
1 java -jar arthas-boot.jar -h
二、简单使用
1.下载官方提供的Demo并启动
arthas-demo是一个简单的程序,每隔一秒生成一个随机数,再执行质因式分解,并打印出分解结果。
1 wget https://alibaba.github.io/arthas/arthas-demo.jar 2 java -jar arthas-demo.jar
2.重新java -jar启动下载好的arthas jar包
1 java -jar arthas-boot.jar
启动完将看到:
1 ? githubTools java -jar arthas-boot.jar 2 [INFO] arthas-boot version: 3.1.0 3 [INFO] Found existing java process, please choose one and hit RETURN. 4 * [1]: 6419 arthas-demo.jar 5 [2]: 823
3.选择应用java进程
Demo进程是第1个,则输入1,再输入回车/enter。Arthas会attach到目标进程上,并输出日志:
1 [INFO] arthas home: /Users/zhangboqing/.arthas/lib/3.1.0/arthas 2 [INFO] Try to attach process 6419 3 [INFO] Attach process 6419 success. 4 [INFO] arthas-client connect 127.0.0.1 3658 5 ,---. ,------. ,--------.,--. ,--. ,---. ,---. 6 / O \ | .--. ‘‘--. .--‘| ‘--‘ | / O \ ‘ .-‘ 7 | .-. || ‘--‘.‘ | | | .--. || .-. |`. `-. 8 | | | || |\ \ | | | | | || | | |.-‘ | 9 `--‘ `--‘`--‘ ‘--‘ `--‘ `--‘ `--‘`--‘ `--‘`-----‘ 10 11 12 wiki: https://alibaba.github.io/arthas 13 version: 3.1.0 14 pid: 6419 15 time: 2019-02-16 23:22:11 16 17 $
这样就进入到对应的进程中了,接下来的操作都是在当前进程中的
3.简单命令介绍
1)dashboard
输入dashboard,按回车/enter,会展示当前进程的信息,按ctrl+c可以中断执行。
1 ID NAME GROUP PRIORITY STATE %CPU TIME INTERRUPTED DAEMON 2 21 Timer-for-arthas-dashboard-b47de3b0-268b-4d6 system 10 RUNNABLE 76 0:0 false true 3 15 nioEventLoopGroup-3-1 system 10 RUNNABLE 23 0:0 false false 4 11 AsyncAppender-Worker-arthas-cache.result.Asy system 9 WAITING 0 0:0 false true 5 9 Attach Listener system 9 RUNNABLE 0 0:0 false true 6 3 Finalizer system 8 WAITING 0 0:0 false true 7 2 Reference Handler system 10 WAITING 0 0:0 false true 8 4 Signal Dispatcher system 9 RUNNABLE 0 0:0 false true 9 19 as-command-execute-daemon system 10 TIMED_WAITING 0 0:0 false true 10 13 job-timeout system 9 TIMED_WAITING 0 0:0 false true 11 1 main main 5 TIMED_WAITING 0 0:0 false false 12 14 nioEventLoopGroup-2-1 system 10 RUNNABLE 0 0:0 false false 13 18 nioEventLoopGroup-2-2 system 10 RUNNABLE 0 0:0 false false 14 16 pool-1-thread-1 system 5 TIMED_WAITING 0 0:0 false false 15 17 pool-2-thread-1 system 5 WAITING 0 0:0 false false 16 17 18 19 20 21 Memory used total max usage GC 22 heap 39M 123M 1820M 2.16% gc.ps_scavenge.count 3 23 ps_eden_space 28M 32M 672M 4.20% gc.ps_scavenge.time(ms) 32 24 ps_survivor_space 4M 5M 5M 99.38% gc.ps_marksweep.count 0 25 ps_old_gen 6M 85M 1365M 0.45% gc.ps_marksweep.time(ms) 0 26 nonheap 19M 20M -1 96.34% 27 code_cache 4M 4M 240M 1.78% 28 metaspace 13M 13M -1 96.48% 29 compressed_class_space 1M 1M 1024M 0.16% 30 direct 0K 0K - Infinity% 31 Runtime 32 os.name Mac OS X 33 os.version 10.14 34 java.version 1.8.0_112 35 java.home /Library/Java/JavaVirtualMachines/jdk1.8.0_1 36 12.jdk/Contents/Home/jre 37 systemload.average 1.69 38 processors 4
2)thread
通过thread命令来获取到arthas-demo进程的Main Class
thread 1会打印线程ID 1的栈,通常是main函数的线程。
1 $ thread 1 2 "main" Id=1 TIMED_WAITING 3 at java.lang.Thread.sleep(Native Method) 4 at java.lang.Thread.sleep(Thread.java:340) 5 at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386) 6 at demo.MathGame.main(MathGame.java:17) 7 8 Affect(row-cnt:0) cost in 17 ms.
3)jad
通过jad来反编译Main Class
1 $ jad demo.MathGame 2 3 ClassLoader: 4 +-sun.misc.Launcher$AppClassLoader@6bc7c054 5 +-sun.misc.Launcher$ExtClassLoader@7e97d617 6 7 Location: 8 /Users/zhangboqing/Software/githubTools/arthas-demo.jar 9 10 /* 11 * Decompiled with CFR 0_132. 12 */ 13 package demo; 14 15 import java.io.PrintStream; 16 import java.util.ArrayList; 17 import java.util.Iterator; 18 import java.util.List; 19 import java.util.Random; 20 import java.util.concurrent.TimeUnit; 21 22 public class MathGame { 23 private static Random random = new Random(); 24 public int illegalArgumentCount = 0; 25 26 public static void main(String[] args) throws InterruptedException { 27 MathGame game = new MathGame(); 28 do { 29 game.run(); 30 TimeUnit.SECONDS.sleep(1L); 31 } while (true); 32 } 33 34 public void run() throws InterruptedException { 35 try { 36 int number = random.nextInt() / 10000; 37 List<Integer> primeFactors = this.primeFactors(number); 38 MathGame.print(number, primeFactors); 39 } 40 catch (Exception e) { 41 System.out.println(String.format("illegalArgumentCount:%3d, ", this.illegalArgumentCount) + e.getMessage()); 42 } 43 } 44 45 public static void print(int number, List<Integer> primeFactors) { 46 StringBuffer sb = new StringBuffer("" + number + "="); 47 Iterator<Integer> iterator = primeFactors.iterator(); 48 while (iterator.hasNext()) { 49 int factor = iterator.next(); 50 sb.append(factor).append(‘*‘); 51 } 52 if (sb.charAt(sb.length() - 1) == ‘*‘) { 53 sb.deleteCharAt(sb.length() - 1); 54 } 55 System.out.println(sb); 56 } 57 58 public List<Integer> primeFactors(int number) { 59 if (number < 2) { 60 ++this.illegalArgumentCount; 61 throw new IllegalArgumentException("number is: " + number + ", need >= 2"); 62 } 63 ArrayList<Integer> result = new ArrayList<Integer>(); 64 int i = 2; 65 while (i <= number) { 66 if (number % i == 0) { 67 result.add(i); 68 number /= i; 69 i = 2; 70 continue; 71 } 72 ++i; 73 } 74 return result; 75 } 76 } 77 78 Affect(row-cnt:1) cost in 830 ms. 79 $
4)watch
通过watch命令来查看demo.MathGame#primeFactors函数的返回值:
1 watch demo.MathGame primeFactors returnObj 2 Press Q or Ctrl+C to abort. 3 Affect(class-cnt:1 , method-cnt:1) cost in 59 ms. 4 ts=2019-02-16 23:31:38; [cost=1.710847ms] result=null 5 ts=2019-02-16 23:31:39; [cost=0.079354ms] result=null 6 ts=2019-02-16 23:31:40; [cost=0.251734ms] result=@ArrayList[ 7 @Integer[2], 8 @Integer[2], 9 @Integer[2], 10 @Integer[2], 11 @Integer[2], 12 @Integer[2], 13 @Integer[2], 14 @Integer[2], 15 @Integer[5], 16 @Integer[109], 17 ]
4.退出arthas
如果只是退出当前的连接,可以用quit或者exit命令。Attach到目标进程上的arthas还会继续运行,端口会保持开放,下次连接时可以直接连接上。
如果想完全退出arthas,可以执行shutdown命令。
附录:
Arthas 用户文档:https://alibaba.github.io/arthas/quick-start.html
Arthas github地址: https://github.com/alibaba/arthas
原文地址:https://www.cnblogs.com/756623607-zhang/p/10389844.html