《JVM调优》- Jstack指令详解

概述

jstack命令用于打印指定Java进程、核心文件或远程调试服务器的Java线程堆栈的跟踪信息。换句话说,就是jstack能生成JVM当前时刻的线程快照,以此来定位线程出现长时间停顿的原因,最常见应用场景为:

  • 查看线程间死锁
  • 分析CPU过高原因

针对这两个场景,后续会有实战案例~

常用指令

jstack [-option] <pid> // 打印某个进程的堆栈信息

其他常用指令如下:

在这里插入图片描述

指令说明
-F当jstack指令无响应时,强制打印一个堆栈信息
-m打印包含Java和C/C++帧的混合模式堆栈跟踪
-l打印关于锁的其他信息,比如拥有java.util.concurrent ownable同步器的列表
-h / -help打印帮助信息

Jstack实战

案例一:jstack分析死锁

public class DeadLock {

    private static Object lockA = new Object();
    private static Object lockB = new Object();

    public static void main(String[] args) {
        
        new Thread(() ->{
            synchronized (lockA) {
                try {
                    System.out.println("线程1开始运行========");
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                }
                synchronized (lockB) {
                    System.out.println("线程1运行结束========");
                }
            }
        }).start();

        new Thread(() ->{
            synchronized (lockB) {
                try {
                    System.out.println("线程2开始运行========");
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                }
                synchronized (lockA) {
                    System.out.println("线程2结束运行========");
                }
            }
        }).start();
        
        System.out.println("主线程运行结束========");
    }
}

运行结果如下:

线程1开始运行========
主线程运行结束========
线程2开始运行========

可见,线程1和线程2都没有运行完成,两个线程在抢夺资源过程中陷入了死循环

排查思路
  1. 使用jps指令查看当前运行中的java程序
  2. 使用jstack -l < pid > ,输出线程及锁详情
  3. 进行死锁分析
动手实践

那么首先使用jps:
在这里插入图片描述
使用jstack指令:
在这里插入图片描述
在这里插入图片描述
通过上图,可以得到死锁的信息:

"Thread-1":
  waiting to lock monitor 0x000000001d290de8 (object 0x000000076b19b890, a java.lang.Object),
  which is held by "Thread-0"
"Thread-0":
  waiting to lock monitor 0x000000001d293678 (object 0x000000076b19b8a0, a java.lang.Object),
  which is held by "Thread-1"

并且可以定位到对应代码位置,是不是非常的方便~

案例二:jstack分析CPU过高

实例代码如下:

public class CpuProblem {

    private static ExecutorService executorService = Executors.newFixedThreadPool(5);

    public static void main(String[] args) {

        Task task1 = new Task();
        Task task2 = new Task();
        executorService.execute(task1);
        executorService.execute(task2);
    }

    public static Object lock = new Object();

    static class Task implements Runnable {

        public void run() {
            synchronized (lock) {
                long sum = 0L;
                while (true) {
                    sum += 1;
                }
            }
        }
    }
}

排查思路
1. top
2. top -Hp <pid>
3. 获取cpu最高的进程号并转换为16进制<pid_16>
4. jstack <pid>|grep -A 10 <pid_16>
5. 查看对应问题的代码

动手实践
  1. 使用命令top -p ,显示你的java进程的内存情况,pid是你的java进程号,比如19663
    在这里插入图片描述

  2. 按H(获取top -Hp pid指令),获取每个线程的内存情况
    在这里插入图片描述

  3. 找到内存和cpu占用最高的线程tid,比如19664

  4. 转为十六进制得到 0x4cd0,此为线程id的十六进制表示

  5. 执行 jstack 19663|grep -A 10 4cd0,得到线程堆栈信息中 4cd0 这个线程所在行的后面10行,从堆栈中可以发现导致cpu飙高的调 用方法
    在这里插入图片描述

  6. 查看对应的堆栈信息找出可能存在问题的代码

本文转自 https://blog.csdn.net/weixin_38277138/article/details/127397229,如有侵权,请联系删除。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值