现在大部分公司都有自己完整的一套监控系统,比如美团的CAT,我们公司的监控系统也是基于CAT做的二次开发。一般测试环境或生产环境有问题可以直接使用这些系统查看线程和内存运行情况,分析排查问题。

但对于我们开发人员来说还是有必要了解最原始的排查流程,也就是不借助这些系统,使用最基本的命令解决,毕竟了解了这些底层实现对自身发展也是有帮助的。

网上搜下这样的文章其实很多,比如排查cpu过高,死锁问题的文章,但大部分讲的都是Linux环境下怎么做,其实很多问题在本地开发时就能发现和排查,所以我主要讲下Windows环境下如何排查,这里举例讲下java应用出现死锁问题的排查方法。

主要有两种方式,一种是使用JVM指令+Process Explorer工具,另一种是使用jdk/bin目录下的jvisualvm.exe工具

一. JVM指令+Process Explorer

常用JVM指令:

全部命令可参考官方文档说明

Process Explorer是windows系统的进程管理器,可以查看对应pid(进程id)下的线程信息,方便定位到哪个线程占有的cpu资源高。

排查过程:

1. 打开Process Explorer工具,找到自己的java应用,如果不清楚出问题的java进程是哪个,可以在windows的cmd命令窗口里输入jps 指令查看所有java应用的进程id,如图:

Windows环境下如何进行线程dump分析插图

如果还不能确定哪个pid是你的java应用,可以加上 -lm 参数,

即:jps -lm,打印出详细的类名,方便找到对应的pid

还有一种方式是在任务管理器(任务管理器-查看-选择列-pid)里也能找到对应的pid

2. 根据第一步找到的pid在Process Explorer工具找到那一行记录然后双击打开Thread一栏的tab,就能看的java进程pid对应的线程信息,TID就是对应的线程id,如图:

Windows环境下如何进行线程dump分析插图1

3. 在cmd命令行窗口使用jstack指令把java应用的栈信息dump到本地分析,当然也可以直接在命令行窗口分析,但是一般堆栈信息都比较大,所有的线程信息都在里面,我们只关心出问题线程的堆栈信息,这样的话的可以使用: jstack pid|findstr tid 这个指令查找我们关心的线程id,但还是建议dump到本地查找,这里的tid要注意一下,jstack里的线程id是用十六进制表示的,需要把第2步里的tid(十进制)转为十六进制,如图:

Windows环境下如何进行线程dump分析插图2

jstack指令后面的 -l 参数表示输出锁信息

Windows环境下如何进行线程dump分析插图3

4. 打开dump文本文件,通过十六进制的tid找到对应的堆栈信息,就可以定位到具体的业务代码调用位置:

Windows环境下如何进行线程dump分析插图4

从上图可以看出出问题的代码是在DeadLockTest的70行,线程的状态是BLOCKED,因为dump线程时加上了 -l 的参数(jstack -l pid),所以在dump的最下方jvm会输出死锁的信息:

Windows环境下如何进行线程dump分析插图5

很明显Thread-1线程在等待0x000000076b940cf0这个锁,它本身持有0x000000076b940d00这个锁,而Thread-0刚好在等待0x000000076b940d00这个锁,它本身持有的锁是0x000000076b940cf0,这样成了两个线程互相等待对方手里持有的锁,导致了死锁的出现。

二. jvisualvm.exe工具

这个工具在jdk的安装目录的bin文件夹里,打开后也是找到对应的pid,它其实是访问我们jvm虚拟机里的堆栈信息,优点就是直观和方便查看线程运行情况,如果有死锁也会提示出来,如图:

Windows环境下如何进行线程dump分析插图6