jstack 命令的使用和问题排查分析思路

jstack 命令

  • 什么是jstack

  • jstack命令

  • 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");
                }
            }
        }
    }
}

​​​​​​​

输出如下:

如上图所示没有继续输出;继续排查

使用 jps 命令查看


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

第二个thread所示:
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

  • 4
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
jstack命令是JDK中的一个工具,用于打印正在运行的Java进程的线程栈信息。它可以通过以下几种方式使用: 1. 使用jstack命令连接到正在运行的进程,通过指定进程ID来获取线程栈信息。例如,可以使用以下命令查看进程ID为19332的线程堆栈信息: jstack 19332 2. 使用jstack命令连接到已挂起的进程,通过指定进程ID来获取线程栈信息。在某些情况下,jstack命令可能没有响应,可以使用选项"-F"来强制打印线程栈信息。例如,可以使用以下命令查看进程ID为19332的已挂起进程的线程堆栈信息: jstack -F 19332 3. 使用jstack命令连接到核心文件(core file),通过指定可执行文件和核心文件的路径来获取线程栈信息。例如,可以使用以下命令查看可执行文件和核心文件的路径为"executable"和"core"的线程堆栈信息: jstack executable core 除了以上用法外,jstack命令还支持一些选项来获取更详细的信息。例如,选项"-m"可以打印Java栈和本地方法栈,选项"-l"可以打印关于锁的额外信息。 总结来说,jstack命令是JVM自带的Java堆栈跟踪工具,用于生成当前时刻的线程快照,以定位线程出现长时间停顿的原因。它还可以用于获取core文件的Java堆栈和本地方法栈信息,或者附属到正在运行的Java程序中查看实时的线程堆栈信息。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [jstack 命令解读](https://blog.csdn.net/qq_19922839/article/details/115379649)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [jstack命令解析](https://blog.csdn.net/weixin_44588186/article/details/124680586)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值