arthas命令

stack

查看某个方法的调用栈的路径

/**
*.ArthadDemo是对应的类
show是对应的方法名
*/
[arthas@7248]$ stack *.ArthasDemo show
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 77 ms, listenerId: 2
ts=2023-07-21 22:50:17;thread_name=Thread-0;id=e;is_daemon=false;priority=5;TCCL=jdk.internal.loader.ClassLoaders$AppClassLoader@61064425
    @com.example.demo.ArthasDemo.show()
        at com.example.demo.ArthasDemo$1.run(ArthasDemo.java:14)
        at java.lang.Thread.run(Thread.java:834)

//表示利用arthas捕获对应类的show方法3次,也就是打印对应方法3次栈
 stack *.ArthasDemo show -n 3

我们暂时可以忽略-m这个参数 ,可以看下面的trace命令的使用

trace *.ArthasDemo show '#cost > 5' 方法执行时间超过5毫秒的方法的栈

trace

对整个方法的每一个链路的耗时

[arthas@2312]$ trace *.ArthasDemo show
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 84 ms, listenerId: 1
`---ts=2023-07-21 23:49:52;thread_name=Thread-0;id=e;is_daemon=false;priority=5;TCCL=jdk.internal.loader.ClassLoaders$AppClassLoader@61064425
    `---[8017.2216ms] com.example.demo.ArthasDemo:show() //show方法的耗时是8秒
        `---[62.43% 5005.0764ms ] com.example.demo.ArthasDemo:kk() #41 //kk方法的耗时是5秒

trace *.ArthasDemo show -n 3 //表示监控3次

trace *.ArthasDemo show -m 2 类似stace表示处理多少个类(这个命令就是处理不同包下同一个类名ArthasDemo)

trace --skipJDKMethod false` *.ArthasDemo show //包含show中调用jdk中函数的耗时

 trace *.ArthasDemo show '#cost >2' //追踪方法执行时间超过2毫秒的方法

//匹配多个类和多个方法
trace -E com.example.demo.ArthasDemo|com.example.demo.test.ArthasDemo kk|show

//过滤掉不关注的类和方法
过滤掉com.example.demo.ArthasDemo这个类
trace *.ArthasDemo show --exclude-class-pattern com.example.demo.ArthasDemo

watch

//对应的java方法如下
```plaintext
public static int show(int k) {
    System.out.println("test show method");
    try {
        Thread.sleep(4);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return k*3;
}

//查看show方法的返回值
watch *.ArthasDemo show 

//调用之前输入的参数
watch *.ArthasDemo show "{params}" -x 2 -b
method=com.example.demo.test.ArthasDemo.show location=AtEnter
ts=2023-07-22 15:13:01; [cost=0.0127ms] result=@ArrayList[
    @Object[][
        @Integer[28],//输入的参数
    ],
]

//调用后对应的输入的参数和返回值
watch *.ArthasDemo show "{params,returnObj}" -x 2
method=com.example.demo.test.ArthasDemo.show location=AtExit
ts=2023-07-22 15:14:11; [cost=5.3626ms] result=@ArrayList[
    @Object[][
        @Integer[33],
    ],
    @Integer[99],
]

-x 表示遍历的深度,比喻 -x 2 答应的List的对象 -x 3 可能答应的就是每一个List对象的具体属性值


参考如下的博客:https://blog.csdn.net/tec_1535/article/details/125303634
watch 类全限定名 方法名 '{params,throwExp}' -e -x 2:观察异常信息
-e 方法抛出异常时才会有触发输出

watch 类全限定名 方法名 params[0] "params[0]<0"
过滤出入参<0时的入参

watch 类全限定名 方法名 params 'params.length==1'
过滤出入参长度=1时的入参

tt

[arthas@1560]$ tt -t  *.ArthasDemo show

heapdump命令

在多次gc之后,可以看到对应的ThreadLocal对象大部分被GC了,但是A对象的实体并没有被gc,导致ThreadLocal发生了内存泄漏

生成对应的dump文件
 heapdump  D:\heap\dump.hprof 

只dump live对象:
 heapdump --live D:\heap\dump.hprof

/**
线程是线程池的核心线程,所以线程不会被gc回收,但是对应的ThreadLocal在循环中使用完毕之后,会被gc回收
每一个线程Thread对象都有一个ThreadLocal.ThreadLocalMap,它是一个用户hash的数组,里面存储对应的Entry,Entry是一个弱引用
在创建Entry的时候,会将对应的ThreadLocal传入,作为Reference抽象类的referent属性,所以当ThreadLocal被回收之后,那么对应的Entry就会被回收,
但是在创建Entry的时候,传入的value可能是一个强应用,但是Entry被回收了,导致无法访问到Entry中的value,导致内存泄漏
*/
ThreadPoolExecutor tpe = new ThreadPoolExecutor(1,1,10, TimeUnit.SECONDS,new LinkedBlockingDeque<>());
  tpe.execute(new Runnable() {
      @Override
      public void run() {
          int length = 100000;
          int i = 0;

          while (true){
              ThreadLocal threadLocal = new ThreadLocal();
              A a  = new A();
              a.name = "cxk"+Math.random();
              threadLocal.set(a);
              i++;
              if(i>length)break;
          }
          System.gc();
          System.gc();
          System.gc();
          System.gc();
          System.out.println("执行完毕...");
      }
  });
posted on 2023-07-22 00:05  x-cuke  阅读(208)  评论(0)    收藏  举报