使用 jstack 命令排查问题

什么是jstack

jstack是用于生成java虚拟机当前时刻的线程快照。线程快找是当前java虚拟机内存每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因

如果出现死锁,死循环,请求外部资源出现长时间等待等,线程出现停顿的时候,通过jstack来查看各个线程调用堆栈,就知道线程在后台做了什么,或者等待什么资源,如果java程序崩溃生成core文件,jstack工具可以用来获取core文件的java,stack和native stack的信息,从而可以轻松地知道java程序是如何崩溃和在程

程序触发生成的问题,另外,jstack工具还可以附属到正在运行的java程序中看到当时运行的java程序的java stack和native stack的信息, 如果现在运行的java程序呈现bug的状态,jstack是非常有用的。

jstack命令

在这里插入图片描述
参数说明:

  • -F 当 ‘jstack [-l] pid’ 没有响应的时候强制打印栈信息,如果直接jstack无响应时,用于强制jstack,一般情况下无需使用

  • -l 长列表 打印关于锁定附加信息,例如属于:java.util.concurrent的ownable synchronizers列表会使jvm停顿的长久的多,

  • -m 打印java和native c/c++ 框架的所有栈信息.可以打印JVM的堆栈,显示上Native的栈帧,一般应用排查不需要使用

执行命令

jstack -m 12905

在这里插入图片描述
科普一下线程状态:

NEW未启动的。不会出现在Dump中
RUNNABLE在虚拟机内执行的
BLOCKED受阻塞并等待监视器锁
WATING无限期等待另一个线程执行特定操作。
TIMED_WATING有时限的等待另一个线程的特定操作
TERMINATED已退出的

jstack实战操作

现在假设一个场景,在几乎没有什么调用的情况下,服务器的cpu的使用率一直居高不下非常有可能是程序中出现死循环导致的,当然在业务量不大的情况下,如果cpu占用率过高,除了死循环以外,常见的还有,内存泄漏,导致大量的full GC

jstack实战之cpu 占用过高-----测试代码

/**
 * @Auther: corey
 * @Date: 2020/8/5 14:25
 * @Description: jstack 测试代码
 */

public class JstackTest {
 private static Executor executor = Executors.newFixedThreadPool(5);
    private static final Object lock = new Object();
    public static void main(String[] args) {
        MyRunnableImpl myRunnable = new MyRunnableImpl();
        MyRunnableImpl myRunnable1 = new MyRunnableImpl();
        executor.execute(myRunnable);
        executor.execute(myRunnable1);
    }
    static class MyRunnableImpl implements Runnable{

        @Override
        public void run() {
            synchronized (lock){
                //死循环
                calculate();
            }
        }
        private void calculate(){
            int i = 0;
            while (true){
                i++;
            }
        }
    }
}

在这里插入图片描述
使用top命令可以看到,cpu的占用到99%了,使用 jps命令查看当前java 程序运行的有哪些。
在这里插入图片描述
然后使用 jstack 4275 命令查看当前程序出现死循环的是在哪一行
在这里插入图片描述
如下上图,JstackTest 程序的 31行
在这里插入图片描述
①线程名。

②线程优先级。

③一个地址(该地址是什么地址,存疑)。

④线程十六进制id。

⑤线程状态。

⑥线程当前所处方法。

⑦该箭头表示线程的执行历程。

jstack实战之死锁线程的定位-----测试代码

/**
 * @Auther: corey
 * @Date: 2020/8/5 15:01
 * @Description:死锁线程的定位
 */
public class JstackLockTest {

    private static Executor executor = Executors.newFixedThreadPool(5);

    private static final Object lockA = new Object();

    private static final Object lockB = new Object();

    public static void main(String[] args) {
        MyRunnableImplOne th1 = new MyRunnableImplOne();
        MyRunnableImplTwo th2 = new MyRunnableImplTwo();

        executor.execute(th1);
        executor.execute(th2);
    }

    static class MyRunnableImplOne implements Runnable {

        @Override
        public void run() {
            synchronized (lockA) {
                System.out.println(Thread.currentThread().getName() + "获得了锁LockA");
                //循环
                int i = 10;
                while (i > 10) {
                    i--;
                }
                synchronized (lockB) {
                    System.out.println(Thread.currentThread().getName() + "获得了锁B");
                }
            }
        }
    }

    static class MyRunnableImplTwo implements Runnable {
        @Override
        public void run() {
            synchronized (lockB) {
                System.out.println(Thread.currentThread().getName()+"获得了锁lockB");
                int i = 10;
                while (i > 10) {
                    i--;
                }
                synchronized (lockA) {
                    System.out.println(Thread.currentThread().getName()+"获得了锁lockA");
                }
            }
        }
    }
}

输出如下:
在这里插入图片描述
如上图所示没有继续输出;继续排查

  • 1 使用 jps 命令查看
    在这里插入图片描述
    使用jstack pid指令,查看指定进程的堆栈信息,观察并定位到死锁线程。
    在这里插入图片描述
    上图可以看到,线程 pool-1-thread-2已经获取到了地址 <0x000000076ae309a0> 正在 java.lang.Thread.State: BLOCKED 等待获取地址为 <0x000000076ae309b0> 的对象锁,

第二个如图所示:
pool-1-thread-1 已经获取到了地址为<0x000000076ae309b0>的地址,正在BLOCKED等待地址为 <0x000000076ae309a0>的对象锁

上述分析过程是对死锁和cpu 超高的情况下的场景分析,我们可以通过诸如【统一获取锁的顺序(线程按照一定的顺序加锁)】、【设置获取锁的超时时间(线程尝试获, 取锁的时候加上一定的时限,超过时限则放弃对该锁的请求,并释放自己占有的锁)】、【死锁检测】等手段预防死锁发生。但是如果一旦发生了死锁就没法解开了,只能停掉程序,修复bug后再启动服务了。

参考:https://www.cnblogs.com/taiguyiba/p/9470861.html
https://blog.csdn.net/justry_deng/article/details/90447410

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值