前言
如果有一天,你的Java程序暂停了很长时间,可能是生病了,需要用jstack拍一个片子来分析,以便诊断具体的疾病,比如死锁综合征或者其他疾病比如无限循环。在这篇文章中,让我们一起学习jstack命令~
jstack的功能
jstack的用法
线程状态的基本审查等
实际案例1: jstack分析死锁
实际案例2: jstack分析CPU过高
jstack的功能
Jstack是JVM自带的java栈跟踪工具,用于打印出给定Java进程ID、核心文件和远程调试服务的Java栈信息。
jstack命令用于在当前时间生成虚拟机的线程快照。
线程快照是当前虚拟机中每个线程正在执行的方法堆栈的集合。生成线程快照的主要目的是定位导致线程长时间停滞的原因,如线程之间的死锁、循环无休以及请求外部资源导致的长时间等待。
当一个线程暂停时,可以通过jstack检查每个线程的调用栈,就可以知道没有响应的线程在后台做什么,或者在等待什么资源。
如果一个java程序崩溃生成了一个核心文件,可以使用jstack工具获取核心文件的java栈和本机栈的信息,这样就可以很容易地知道java程序是如何崩溃的,程序出了什么问题。
此外,还可以在运行的java程序上附加jstack工具,查看当时运行的java程序的java栈和本机栈的信息。如果运行的Java程序处于挂起状态,jstack非常有用。
jstack的用法
jstack命令的格式如下
生成核心转储的可执行Java可执行文件。
由Core打印的信息的core转储文件
远程调试服务的远程主机名或ip主机名或IP
服务器id唯一id,如果一台主机上有多个远程调试服务
最常用的是
选项参数描述如下:
线程状态的基本审查等
线程状态介绍
Jstack用于生成线程快照。我们需要通过分析线程情况来查看线程状态。拿个小凳子复习一下~
Java语言定义了六种线程池状态:
新:创建后未启动的线程处于此状态,不会出现在转储中。
可运行:包括运行和就绪。当线程打开start方法时,它将进入此状态并在虚拟机中执行。
等待:无限等待另一个线程的具体操作。
定时等待:在有限的时间内等待另一个线程的特定操作。
阻塞:当程序等待进入同步区时,线程会进入这种状态,等待监视器锁定。
End:线程的线程状态已经终止,线程已经执行完毕。
通常,转储文件的线程状态如下:
RUNNABLE,线程正在执行
BLOCKED,线程被阻塞
等待,线程正在等待
监视器监视器锁定
由于Java程序通常是通过多线程运行的,而Java多线程是和监控锁链接在一起的,所以我们在分析线程状态时需要复习Monitor监控锁的知识。
监视器的工作原理图如下:
如果一个线程想要获得监视器,它将首先进入入口集队列,这是等待线程,线程状态是等待监视器入口。
当一个线程成功获得一个对象的监视器时,它进入所有者区域,它被称为活动线程。
如果线程调用等待方法,它将进入等待集队列,这将释放监视器锁,监视器锁也是等待线程,线程状态是inobject.wait。
如果其他线程调用notify/notifyAll,它将唤醒等待集中的一个线程,如果成功,该线程将尝试再次获取监视器锁并进入所有者区域。
转储文件分析的重点
可运行,线程正在执行
僵局,僵局
阻塞,线程被阻塞
停车,停车
锁定,对象被锁定
等待,线程正在等待
等待锁定等待锁定
对象。等待,对象正在等待
等待监视器输入等待获取监视器
等待条件,等待资源,最常见的情况是线程在网络上等待读写
实际案例1: jstack分析死锁问题
什么是死锁?
如何用jstack解决死锁?
什么是死锁?
死锁是指在执行过程中,两个或多个线程因为争夺资源而相互等待的现象。如果没有外力,他们将无法进行。
如何使用jstack解决死锁问题
我们先来看一个会产生死锁的Java程序。源代码如下:
运行结果:
很明显,线程jay和线程罗天只是执行到一半,他们陷入了阻塞等待状态~
Jstack死锁故障排除步骤
在终端输入jsp查看当前运行的java程序
使用jstack -l pid查看线程堆栈信息
分析堆栈信息
在终端输入jsp查看当前运行的java程序
通过使用jps命令获取要监控的进程的pid,我们发现
使用jstack -l pid查看线程堆栈信息
从上图中可以清楚地看到死锁信息:
mythread-罗天等待由mythread-jay线程持有的锁“0x00000000d61ae3a0”。
mythread-jay线程等待由mythread-罗天线程持有的锁“0x00000000d61ae3d0”。
恢复死锁真相
“神话-罗天”线程堆栈信息分析如下:
mythread-罗天的线程处于等待状态,持有“0x00000000d61ae3d0”的锁,等待“0x00000000d61ae3a0”的锁
对“mythread-jay”线程堆栈信息的分析如下:
mythread-罗天的线程处于等待状态,持有“0x 00000000 d61a 3 a 0”的锁,等待“0x 00000000 d61a 3d 0”的锁
实际案例2: jstack分析了CPU过度的问题
来个导致CPU过高的演示程序,无限循环,哈哈~
Jstack分析CPU高步进
顶端
top-惠普pid
jstack pid
jstack -l >/tmp/log.txt
分析堆栈信息
1 .顶部
在服务器上,我们可以通过top命令检查每个进程的cpu使用情况,默认情况下,top命令是从高到低排序的
从上图我们可以找出占用cpu资源最高的pid为21340的java进程,凶手就是它,哈哈!
2.top-惠普pid
使用top -Hp 21340,您可以在此过程中检查每个线程的cpu使用情况,如下所示:
可以发现pid为21350的线程占用的CPU资源最高~,嘻嘻,写在小本子上,然后拿jstack去拍~
3.jstack pid
使用top命令定位cpu利用率高的线程,然后使用jstack pid命令查看当前java进程的堆栈状态。之后,内容如下:
4.jstack -l >/tmp/log.txt
事实上,堆栈信息已经在前三步中出来了。但是一般在生成环境中,我们可以把这些栈信息打成文件,然后仔细分析~
5.分析堆栈信息
我们采用占用大量cpu资源的线程pid,并将pid转换为十六进制值
在线程转储中,每个线程都有一个nid,我们找到相应的nid并发现它一直在运行
这时可以检查代码是否有问题~当然也建议隔一段时间执行一次stack命令,然后得到线程转储。毕竟两次拍摄结果的对比还是比较准确的~