[JVM]JDK自带分析工具jstack简单分析

目录

前言

线上问题

jps -lvm

jstack -l pid

jstack -l > xxxx.jstack

说明

常用参数

网上的一些使用方式

top命令

实例1:多线程竞争synchronized锁

实例2:通过wait挂起线程

总结


前言

前面写了jmap 和 visualVM,

jstack在实际生产中也用到过,不过当时都记在印象笔记了~

其实都是总结学习吧,因为之前在职,很多东西没时间写博客。就简单记录在笔记上面了。

这次刷题准备面试,记录博客也是让自己知识更成体系吧。 时间浪费点希望能有更多的价值。

虽然选择高优的事情直接背八股文更加效率,但是我喜欢慢工出细活,欲速则不达。

线上问题

我们查询内容质量校验的时候,

发现,查询hive可能线程卡死了

因为使用线程池做的数据查询。

但是有的日志并不连续,感觉像是没有执行完的样子。

很偶现的事情,后续把日志打印完成,该进行异常处理的都处理,并打印日志,后续就没有发生这个问题了。

jps -lvm

jps -lvm 用于查看当前机器上运行的java进程。

然后用:

jstack -l pid

我们使用 jstack -l 6812 查看我们的应用堆栈信息:

"G1 Concurrent Refinement Thread#11" os_prio=0 tid=0x00007f96b0050800 nid=0x186f runnable

只是看当前堆栈的信息,历史信息并不能看到。

并没法复现现场,因为是0点之后才会做数据质量的校验。

jstack -l > xxxx.jstack

jstack 是一个抓取 thread dump 文件的有效的命令行工具,它位于 JDK 目录里的 bin 文件夹下(JDK_HOMEbin),以下是抓取 dump 文件的命令:

jstack -l > 

比如:

jstack -l 6227 >6227.jstack

文件就不放出了,之后可以用fastthread.io分析:[JVM]dump分析工具_fastthread.io

说明

jstack,主要分析线程问题,跟jmap主要分析OOM和堆内存问题不同。

主要用来跟踪java进程中的线程的执行状态,比较重要。

jstack pid;  //可以打印出进程中线程的栈,及状态;

作用:

线程发生问题-死锁;

线程状态;

常用参数

localhost:~ bjhl$ jstack -h
Usage:
    jstack [-l] <pid>
        (to connect to running process)
    jstack -F [-m] [-l] <pid>
        (to connect to a hung process)
    jstack [-m] [-l] <executable> <core>
        (to connect to a core file)
    jstack [-m] [-l] [server_id@]<remote server IP or hostname>
        (to connect to a remote debug server)

Options:
    -F  to force a thread dump. Use when jstack <pid> does not respond (process is hung)
    -m  to print both java and native frames (mixed mode)
    -l  long listing. Prints additional information about locks
    -h or -help to print this help message

这边可能会引出,线程的几种状态和生命周期等等

网上的一些使用方式

该部分来自:如何使用jstack分析线程状态

作者:Jessica程序猿

大概就是:

测试环境的服务器cpu使用率一直处于100%,本地又没有什么接口调用,为什么会这样?cpu使用率居高不下,自然是有某些线程一直占用着cpu资源,那又如何查看占用cpu较高的线程?

top命令

在linux环境下,可以通过top命令查看各个进程的cpu使用情况,默认按cpu使用率排序

1、看出pid为23344的java进程占用了较多的cpu资源;
2、通过top -Hp 23344可以查看该进程下各个线程的cpu使用情况;

从进程,找到线程, 然后用jstack:

占了较多的cpu资源,利用jstack命令可以继续查看该线程当前的堆栈状态。

 

jstack pid

通过top命令定位到cpu占用率较高的线程之后,继续使用jstack pid命令查看当前java进程的堆栈状态

jstack命令生成的thread dump信息包含了JVM中所有存活的线程,为了分析指定线程,必须找出对应线程的调用栈,应该如何找?

在top命令中,已经获取到了占用cpu资源较高的线程pid,将该pid转成16进制的值,在thread dump中每个线程都有一个nid,找到对应的nid即可;隔段时间再执行一次stack命令获取thread dump,区分两份dump是否有差别,在nid=0x246c的线程调用栈中,发现该线程一直在执行JstackCase类第33行的calculate方法,得到这个信息,就可以检查对应的代码是否有问题。

实例1:多线程竞争synchronized锁

很明显:线程1获取到锁,处于RUNNABLE状态,线程2处于BLOCK状态
1、locked <0x000000076bf62208>说明线程1对地址为0x000000076bf62208对象进行了加锁;
2、waiting to lock <0x000000076bf62208> 说明线程2在等待地址为0x000000076bf62208对象上的锁;
3、waiting for monitor entry [0x000000001e21f000]说明线程1是通过synchronized关键字进入了监视器的临界区,并处于"Entry Set"队列,等待monitor

实例2:通过wait挂起线程

static class Task implements Runnable {
    @Override
    public void run() {
        synchronized (lock) {
            try {
                lock.wait();
                //TimeUnit.SECONDS.sleep(100000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

dump结果

线程1和2都处于WAITING状态

(这边代码不全,我理解是 用了一个对象当锁,所以都需要等同一个对象。)
1、线程1和2都是先locked <0x000000076bf62500>,再waiting on <0x000000076bf62500>,之所以先锁再等同一个对象,是因为wait方法需要先通过synchronized获得该地址对象的monitor;
2、waiting on <0x000000076bf62500>说明线程执行了wait方法之后,释放了monitor,进入到"Wait Set"队列,等待其它线程执行地址为0x000000076bf62500对象的notify方法,并唤醒自己

(这部分需要多理解一下,Object.wait/notify实现机制,如果只是wait不换型出现什么)

 

总结

通过top命令定位到cpu占用率较高的线程之后,继续使用jstack pid命令查看当前java进程的堆栈状态(因为jstack pid 只能打印出对应的java进程的所有栈信息,所以需要找到对应的线程,需要转一下16进制)

在top命令中,已经获取到了占用cpu资源较高的线程pid,将该pid转成16进制的值,在thread dump中每个线程都有一个nid,找到对应的nid即可; 可以用来把thread dump的东西分析出来。

然后隔一段时间,在打印一下当前的线程调用栈的信息,查看一下代码是否有问题。

在dump中,线程一般存在如下几种状态:
1、RUNNABLE,线程处于执行中
2、BLOCKED,线程被阻塞
3、WAITING,线程正在等待

jstack命令主要用来查看Java线程的调用堆栈的,可以用来分析线程问题(如死锁)。

jstack用于生成java虚拟机当前时刻的线程快照。

线程快照是当前java虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等。

线程出现停顿的时候通过jstack来查看各个线程的调用堆栈,就可以知道没有响应的线程到底在后台做什么事情,或者等待什么资源。

如果java程序崩溃生成core文件,jstack工具可以用来获得core文件的java stack和native stack的信息,从而可以轻松地知道java程序是如何崩溃和在程序何处发生问题。

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