java性能分析--线程转储分析工具【jstack】

1,611 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第14天,点击查看活动详情

前一篇文章讲解了jinfo命令,用来查看关于jvm相关信息。本章我们来学习下jstack命令,看看它能帮助我们解决那些JVM的问题。

什么是线程转储?

在前面讲解的jmap一文当中,我们还介绍了什么是堆转储文件。而本章学习的jstack,将会向大家介绍一下什么是线程转储信息

线程转储(Thread Dump),就是jvm当中线程的状态的一次快照信息。学习过java的应该都知道线程包含多种状态,可以参考下面这篇文章:java并发编程(三)java线程状态与方法

通常我们会将线程转储文件保存到文本文件中,可以直接查看,或通过api查看。内部包含了线程的行为,对于排查问题非常的有用。

jstack

jstack用来转储java进程的栈信息。

通过帮助文档查看其使用方式:

[root@hecs-402944 ~]# 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 [-l] <pid>

下面分别看下几个参数什么含义:

  • -F 强制线程转储。当jstack pid线程没有响应的时候。
  • -m 打印java进程信息和native信息(C++,本地方法栈)
  • -l 打印同步器和锁的相关信息。

我们在使用的时候不会直接让它在控制台直接输出,而是生成txt文件,使用> xxx.txt的方式。

获取线程pid:

[root@hecs-402944 opt]# jps
21203 jar
5494 Jps

强制输出

    jstack -F 21203 > 21203.txt

此时生成了文件21203.txt在当前文件夹:

image.png

打开看看:

image.png

如上所示可以看到所有线程的状态,和此线程栈的调用。还包括死锁deadlock的信息,只不过当前服务没有死锁存在。

打印native的信息

     jstack -F -m  21203 > 21203-native.txt

如下所示,仍然有输出内容,但是具体的展示方式是不同的,但是同样包含线程的状态和调用栈,以及死锁信息:

image.png

打印同步器和锁信息

jstack -F -l  21203 > 21203-locks.txt

能够明显感觉到,导出此类信息,耗时增加。目测应该会导致应用暂停,发生gc操作,所以生产还是慎用。

打开看看内容,增加了同步器相关内容:

image.png

jstack使用方式

前面已经介绍了如何使用了,为何又有一个使用方式的小章节?

本小节将会介绍在实际环境中如何使用jstack去发现问题,建议收藏。

  • 假设我们发现服务器的CPU飙高,那么可以按照如下的步骤去操作:

    • top命令,找到占用CPU高的进程(举例一个进程:PID-1)。

    • top -Hp PID-1 查看进程下的线程占用cpu情况(举例该命令查到的线程PID-2)。

    • 将线程PID2转换为16进制:printf "%x\n" PID-2(堆栈中,线程id是以16进制存储的)

    • 使用jstack -l PID-1 >jvm_listlock.txt输出dump信息到堆栈。用步骤3中的16进制id去找到存在问题的代码行。

注意:上述步骤不适用于openjdk,因为本文使用的是openjdk,上面的图示都可以返现,线程的id并非是16进制,直接可以通过PID-2进行查询。

总结

本文介绍了jstack的使用和实际场景如何发现问题,对于我们日常工作当中分析问题,效果还是很明显的。

需要注意的是,导出线程转出文件是还是会对服务器产生性能影响,生产环境慎重使用。