• 概述
    Arthas是一个开源的线上诊断工具,可以实时查看线上代码运行情况,详情参考Arthas
  • 安装
    1.下载jar包即可 https://alibaba.github.io/arthas/arthas-boot.jar
    2.以jar的允许方式就可以了
java -jar arthas-boot.jar  进程id(可使用jps列出所有jvm进程)

java生成诊断报告_System

  • 命令列表
  • jad命令(获取已加载类的源码)
//主要用来看已经加载了类的源码,一般用于动态加载的class的源码比较方便
[arthas@773]$ jad com/example/jvm/Hello

ClassLoader:
+-sun.misc.Launcher$AppClassLoader@18b4aac2
  +-sun.misc.Launcher$ExtClassLoader@362d9542

Location:
/Users/wuxinxin/IdeaProjects/javaseTest/target/classes/

/*
 * Decompiled with CFR.
 */
package com.example.jvm;

import java.io.IOException;

public class Hello {
    public static void main(String[] args) throws IOException {
        System.out.println("Hello, World");
        System.in.read();
    }
}

Affect(row-cnt:1) cost in 354 ms.
  • ognl(查看静态变量值)
[arthas@909]$ ognl @com.example.jvm.Hello@list.size()
@Integer[2]
[arthas@909]$
[arthas@909]$ ognl @com.example.jvm.Hello@list
@ArrayList[
    @String[aa],
    @String[cc],
]
  • trace(跟踪指定方法的执行耗时情况)
  • java生成诊断报告_开发语言_02

  • 说明:可以很好的跟踪线上运行耗时情况,打印线上实时的执行耗时情况
  • watch(查看某方法的参数列表和结果)
    语法:watch 类全路径名 方法名称 ‘{入参对象(Object数组params)和Object结果对象returnObj}’
[arthas@1359]$ watch  com.example.jvm.arthas.UserService delUser '{params,returnObj.toString()}'
Press Q or Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 43 ms.
ts=2020-05-24 16:29:53; [cost=1.942564ms] result=@ArrayList[
    @Object[][isEmpty=false;size=1],
    @String[[liujing, wxx2222, wxx3333]],
]
[arthas@1359]$ watch  com.example.jvm.arthas.UserService checkUser '{params,returnObj.toString()}'
Press Q or Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 12 ms.
ts=2020-05-24 16:30:53; [cost=0.151088ms] result=@ArrayList[
    @Object[][isEmpty=false;size=1],
    @String[0],
]
[arthas@1359]$ watch  com.example.jvm.arthas.UserService checkUser '{params[0],returnObj.toString()}'
Press Q or Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 9 ms.
ts=2020-05-24 16:31:53; [cost=0.125463ms] result=@ArrayList[
    @Integer[0],
    @String[0],
]
  • stack(查看运行时某方法的调用栈)
[arthas@1415]$ stack com.example.jvm.arthas.UserService checkUser
Press Q or Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 43 ms.
ts=2020-05-24 16:58:49;thread_name=main;id=1;is_daemon=false;priority=5;TCCL=sun.misc.Launcher$AppClassLoader@18b4aac2
    @com.example.jvm.arthas.UserService.checkUser()
        at com.example.jvm.arthas.UserService.delUser(UserService.java:58)
        at com.example.jvm.arthas.ArthasTest.main(ArthasTest.java:39)
  • tt命令(又称为时空隧道,就是可以记录当时调用情况,并且可以重复执行)
//tt -t 类路径名称 方法名称(命令执行那一刻,会记录这个方法的所有执行记录)
[arthas@1642]$ tt -t  com.example.jvm.arthas.UserService delUser
Press Q or Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 42 ms.
 INDEX   TIMESTAMP          COST(ms)  IS-RE  IS-EXP  OBJECT        CLASS                        METHOD
                                      T
----------------------------------------------------------------------------------------------------------------------------
 1000    2020-05-24 17:35:  2.019116  true   false   0x5fd0d5ae    UserService                  delUser
         05
//tt -i index 可以查看某个记录详情,甚至可以看到入参和返回值
[arthas@1642]$ tt -i 1000
 INDEX          1000
 GMT-CREATE     2020-05-24 17:35:05
 COST(ms)       2.019116
 OBJECT         0x5fd0d5ae
 CLASS          com.example.jvm.arthas.UserService
 METHOD         delUser
 IS-RETURN      true
 IS-EXCEPTION   false
 PARAMETERS[0]  @Integer[0]
 RETURN-OBJ     @ArrayList[
                    @String[liujing],
                    @String[wxx2222],
                    @String[wxx3333],
                ]
Affect(row-cnt:1) cost in 6 ms.

//tt -i index -p可以在当时条件下,再重复调用(慎用,发生真实调用)
[arthas@1642]$ tt -i 1000 -p
 RE-INDEX       1000
 GMT-REPLAY     2020-05-24 17:40:35
 OBJECT         0x5fd0d5ae
 CLASS          com.example.jvm.arthas.UserService
 METHOD         delUser
 PARAMETERS[0]  @Integer[0]
 IS-RETURN      true
 IS-EXCEPTION   false
 COST(ms)       0.674845
 RETURN-OBJ     @ArrayList[
                    @String[wxx2222],
                    @String[wxx3333],
                ]
Time fragment[1000] successfully replayed 1 times.
  • thread命令(查看线程状态)
[arthas@1642]$ thread
//这里展示当前jvm进程的所有线程情况,有几个比较重要的字段需要关注
//1.name 是线程的名称
//2.state表示线程状态
    a.BLOCKED 一般使用了 synchronized的锁等待
    b.WAITING 一般是无限等待,需要唤醒 park(reentrantLock.lock()内部是park方式实现,这种锁等待也是这种状态)
    c.TIMED_WAITI 一般是指有时间的等待,自动唤醒(sleep,LockSupport.parkNanos)
//3.cpu ,如果有cpu飙高情况,可以看看哪个线程导致
//4.thread id 可以看具体线程情况,比如WAITING是在哪里等待,都能看到

java生成诊断报告_jar_03


syn关键字方式加锁状态详情

//BLOCKED状态测试,没抢到锁的是BLOCKED,抢到锁的但是sleep为TIMED_WAI
 public static void main(String[] args) throws Exception {

        ArthasTest arthasTest = new ArthasTest();
       //测试锁的情况

        for(int i=0;i<10;i++){
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    arthasTest.lock1();
                }
            });

            thread.setName("wxx"+i+"线程");

            thread.start();
        }

        System.in.read();
    }
    
    public synchronized void lock1(){

    try {
        Thread.sleep(60000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

}

java生成诊断报告_java_04


lock方式加锁状态

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

        ArthasTest arthasTest = new ArthasTest();

        ReentrantLock reentrantLock=new ReentrantLock();

        for(int i=0;i<10;i++){
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    arthasTest.lock1(reentrantLock);
                }
            });

            thread.setName("wxx"+i+"线程");

            thread.start();
        }

        System.in.read();
    }

public  void lock1(ReentrantLock reentrantLock){

        reentrantLock.lock();
        try {
            Thread.sleep(60000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        reentrantLock.unlock();
    }

java生成诊断报告_jar_05

  • 总结
    1.可以查看线上实时情况,比如cpu飙高,哪个线程,哪行代码
    2.校验允许结果和预期结果,查看stack, 入参和结果
    3.运行时动态加载编译的class,可以直接查看源码
    4.接口执行很慢,可以实时查看接口调用栈的耗时详情