JVM之jstack命令解析

 命令介绍:

        jstack全称叫Java Stack Trace,Java的堆栈跟踪工具,用于生成java虚拟机当前时刻的线程快照。功能主要有两个,1.分析死锁;2.分析CPU过高问题。

线程快照里留意下面几种状态

  • 死锁,Deadlock(重点关注)
  • 等待资源,Waiting on condition(重点关注)
  • 等待获取管程,Waiting on monitor entry(重点关注)
  • 阻塞,Blocked(重点关注)
  • 执行中,Runnable
  • 暂停,Suspended
  • 对象等待中,Object.wait() 或 TIMED_WAITING
  • 停止,Parked

Jstack 命令格式如下

jstack [ option ] pid 查看当前时间点,指定进程的dump堆栈信息。
jstack [ option ] pid > 文件 将当前时间点的指定进程的dump堆栈信息,写入到指定文件中。# 注:若该文件不存在,则会自动生成; 若该文件存在,则会覆盖源文件。
jstack [ option ] executable core 查看当前时间点,core文件的dump堆栈信息。
jstack [ option ] [server_id@]<remote server IP or hostname> 查看当前时间点,远程机器的dump堆栈信息。

option 参数如下:

-F

当正常输出的请求不被响应时,强制输出线程堆栈

-m

打印java和native c/c++框架的所有栈信息。可以打印JVM的堆栈,以及Native的栈帧,一般应用排查不需要使用。

-l

除堆栈外,显示关于锁的附加信息,在发生死锁时可以用jstack -l pid来观察锁持有情况

参数解释:

  • executable: 产生core dump的java可执行程序
  • core: 将被打印信息的core dump文件
  • remote-hostname-or-IP: 远程debug服务的主机名或ip
  • server-id: 唯一id,假如一台主机上多个远程debug服务

以下用两个实战案例来分析这两种情况:

实战案例1:jstack分析死锁

案例代码

public class DeadLockTest {

   private static Object lock1 = new Object();
   private static Object lock2 = new Object();

   public static void main(String[] args) {
      new Thread(() -> {
         synchronized (lock1) {
            try {
               System.out.println("thread1 begin");
               Thread.sleep(6000);
            } catch (InterruptedException e) {
            }
            synchronized (lock2) {
               System.out.println("thread1 end");
            }
         }
      }).start();

      new Thread(() -> {
         synchronized (lock2) {
            try {
               System.out.println("thread2 begin");
               Thread.sleep(6000);
            } catch (InterruptedException e) {
            }
            synchronized (lock1) {
               System.out.println("thread2 end");
            }
         }
      }).start();

      System.out.println("main thread end");
   }
}

排查命令

jstack 进程ID
或
jstack 进程ID| grep 'BLOCKED' -A 15 --color

结果分析:

        通过结果可以看出Thread-3线程锁住了0x00000000f6360238,然后在等待0x00000000f6360228,而Thread-2却却相反,从下面每个线程的第一行ThreadController.java:42可以看到死锁的代码在哪个地方,进而排查出问题所在。

"Thread-3":
        at com.example.threaddemo.ThreadController.lambda$getThread$1(ThreadController.java:42)
        - waiting to lock <0x00000000f6360228> (a java.lang.Object)
        - locked <0x00000000f6360238> (a java.lang.Object)
        at com.example.threaddemo.ThreadController$$Lambda$464/550716470.run(Unknown Source)
        at java.lang.Thread.run(Thread.java:750)
"Thread-2":
        at com.example.threaddemo.ThreadController.lambda$getThread$0(ThreadController.java:30)
        - waiting to lock <0x00000000f6360238> (a java.lang.Object)
        - locked <0x00000000f6360228> (a java.lang.Object)
        at com.example.threaddemo.ThreadController$$Lambda$463/1326723928.run(Unknown Source)
        at java.lang.Thread.run(Thread.java:750)
但用jstack分析死锁的话,在调用链很长的情况下,也很难定位这时可以用使用Arthas进行分析
thread -b

 可以准确知道: 死锁在代码的中的第几行

实战案例2:jstack分析CPU过高问题

 案例代码

public class CpuMath{

    public static final int initData = 666;
    public static User user = new User();

    public int compute() { 
        int a = 1;
        int b = 2;
        int c = (a + b) * 100;
        return c;
    }

    public static void main(String[] args) {
        CpuMath cpuMath= new CpuMath();
        while (true){
            cpuMath.compute();
        }
    }
}

排查命令流程

1. top

        获取各个进程的CPU和内存情况,并且找到CPU飙高的进程ID,比如进程ID=10843

2. top -p 进程ID

        显示你的java进程的CPU和内存占用情况

3. H

        按H,可以获取每个线程的CPU和内存占用情况,如果线程ID=46915

4.  jstack 进程ID | grep -A 10  十六进制的线程ID

        通过上面的命令,可以得到线程的堆栈信息后10行信息,从堆栈中可以发现导致CPU飙高的调用方法。从打印的堆栈信息可以看出,导致CPU飚高的代码在ThreadController类getThread方法的第21行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值