热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

一段程序结束等待进行下一段程序_给你的Java程序拍个片子吧:jstack命令解析

前言如果有一天,你的Java程序长时间停顿,也许是它病了,需要用jstack拍个片子分析分析,才能诊断具体什么病症ÿ

前言

如果有一天,你的Java程序长时间停顿,也许是它病了,需要用jstack拍个片子分析分析,才能诊断具体什么病症,是死锁综合征,还是死循环等其他病症,本文我们一起来学习jstack命令~

  • jstack 的功能
  • jstack用法
  • 线程状态等基础回顾
  • 实战案例1:jstack 分析死锁
  • 实战案例2:jstack 分析CPU 过高

jstack 的功能

jstack是JVM自带的Java堆栈跟踪工具,它用于打印出给定的java进程ID、core file、远程调试服务的Java堆栈信息.

jstack prints Java stack traces of Java threads for a given Java process or
core file or a remote debug server.

  • jstack命令用于生成虚拟机当前时刻的线程快照。
  • 线程快照是当前虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因, 如线程间死锁、死循环、请求外部资源导致的长时间等待等问题。
  • 线程出现停顿的时候通过jstack来查看各个线程的调用堆栈,就可以知道没有响应的线程到底在后台做什么事情,或者等待什么资源。
  • 如果java程序崩溃生成core文件,jstack工具可以用来获得core文件的java stack和native stack的信息,从而可以轻松地知道java程序是如何崩溃和在程序何处发生问题。
  • 另外,jstack工具还可以附属到正在运行的java程序中,看到当时运行的java程序的java stack和native stack的信息, 如果现在运行的java程序呈现hung的状态,jstack是非常有用的。

jstack用法

jstack 命令格式如下

jstack [ option ] pid
jstack [ option ] executable core
jstack [ option ] [server-id@]remote-hostname-or-IP

  • executable Java executable from which the core dump was produced.(可能是产生core dump的java可执行程序)
  • core 将被打印信息的core dump文件
  • remote-hostname-or-IP 远程debug服务的主机名或ip
  • server-id 唯一id,假如一台主机上多个远程debug服务

最常用的是

jstack [option] // 打印某个进程的堆栈信

option参数说明如下:

3b65fe9b7c2bbf73dd1ca147a772bc2c.png

选项作用

  • -F当正常输出的请求不被响应时,强制输出线程堆栈
  • -m如果调用到本地方法的话,可以显示C/C++的堆栈
  • -l除堆栈外,显示关于锁的附加信息,在发生死锁时可以用jstack -l pid来观察锁持有情况

线程状态等基础回顾

线程状态简介

jstack用于生成线程快照的,我们分析线程的情况,需要复习一下线程状态吧,拿小凳子坐好,复习一下啦~

f502f5aa2a828beba0cd613d32fd4b91.png

Java语言定义了6种线程池状态:

  • New:创建后尚未启动的线程处于这种状态,不会出现在Dump中。
  • RUNNABLE:包括Running和Ready。线程开启start()方法,会进入该状态,在虚拟机内执行的。
  • Waiting:无限的等待另一个线程的特定操作。
  • Timed Waiting:有时限的等待另一个线程的特定操作。
  • 阻塞(Blocked):在程序等待进入同步区域的时候,线程将进入这种状态,在等待监视器锁。
  • 结束(Terminated):已终止线程的线程状态,线程已经结束执行。

Dump文件的线程状态一般其实就以下3种:

  • RUNNABLE,线程处于执行中
  • BLOCKED,线程被阻塞
  • WAITING,线程正在等待

Monitor 监视锁

因为Java程序一般都是多线程运行的,Java多线程跟监视锁环环相扣,所以我们分析线程状态时,也需要回顾一下Monitor监视锁知识。

有关于线程同步关键字Synchronized与监视锁的爱恨情仇,有兴趣的伙伴可以看一下我这篇文章 Synchronized解析——如果你愿意一层一层剥开我的心

Monitor的工作原理图如下:

e9b661830bd6414e99780042cfab2dd4.png
  • 线程想要获取monitor,首先会进入Entry Set队列,它是Waiting Thread,线程状态是Waiting for monitor entry。
  • 当某个线程成功获取对象的monitor后,进入Owner区域,它就是Active Thread。
  • 如果线程调用了wait()方法,则会进入Wait Set队列,它会释放monitor锁,它也是Waiting Thread,线程状态in Object.wait()
  • 如果其他线程调用 notify() / notifyAll() ,会唤醒Wait Set中的某个线程,该线程再次尝试获取monitor锁,成功即进入Owner区域。

Dump 文件分析关注重点

  • runnable,线程处于执行中
  • deadlock,死锁(重点关注)
  • blocked,线程被阻塞 (重点关注)
  • Parked,停止
  • locked,对象加锁
  • waiting,线程正在等待
  • waiting to lock 等待上锁
  • Object.wait(),对象等待中
  • waiting for monitor entry 等待获取监视器(重点关注)
  • Waiting on condition,等待资源(重点关注),最常见的情况是线程在等待网络的读写

实战案例1:jstack 分析死锁问题

  • 什么是死锁?
  • 如何用jstack排查死锁?

什么是死锁?

dc4a271a86108620ec73465a73e0531e.png

死锁是指两个或两个以上的线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法进行下去。

如何用如何用jstack排查死锁问题

先来看一段会产生死锁的Java程序,源码如下:

/*** Java 死锁demo*/
public class DeathLockTest {private static Lock lock1 = new ReentrantLock();private static Lock lock2 = new ReentrantLock();public static void deathLock() {Thread t1 = new Thread() {@Overridepublic void run() {try {lock1.lock();System.out.println(Thread.currentThread().getName() + " get the lock1");Thread.sleep(1000);lock2.lock();System.out.println(Thread.currentThread().getName() + " get the lock2");} catch (InterruptedException e) {e.printStackTrace();}}};Thread t2 = new Thread() {@Overridepublic void run() {try {lock2.lock();System.out.println(Thread.currentThread().getName() + " get the lock2");Thread.sleep(1000);lock1.lock();System.out.println(Thread.currentThread().getName() + " get the lock1");} catch (InterruptedException e) {e.printStackTrace();}}};//设置线程名字,方便分析堆栈信息t1.setName("mythread-jay");t2.setName("mythread-tianluo");t1.start();t2.start();}public static void main(String[] args) {deathLock();}
}

运行结果:

fb70107854143447be96d8e3adf4f04e.png

显然,线程jay和线程tianluo都是只执行到一半,就陷入了阻塞等待状态~

jstack排查Java死锁步骤

  • 在终端中输入jsp查看当前运行的java程序
  • 使用 jstack -l pid 查看线程堆栈信息
  • 分析堆栈信息

在终端中输入jsp查看当前运行的java程序

915b2e139a66135d08262e9565072226.png

通过使用 jps 命令获取需要监控的进程的pid,我们找到了 23780DeathLockTest

使用 jstack -l pid 查看线程堆栈信息

bcd6054abbaf474796e8f980fa12a766.png

由上图,可以清晰看到死锁信息:

  • mythread-tianluo 等待这个锁 “0x00000000d61ae3a0”,这个锁是由于mythread-jay线程持有。
  • mythread-jay线程等待这个锁“0x00000000d61ae3d0”,这个锁是由mythread-tianluo 线程持有。

还原死锁真相

2e5aba3b05dd5cf952f38a6c7e9e233c.png

“mythread-tianluo"线程堆栈信息分析如下:

  • mythread-tianluo的线程处于等待(waiting)状态,持有“0x00000000d61ae3d0”锁,等待“0x00000000d61ae3a0”的锁

“mythread-jay"线程堆栈信息分析如下:

  • mythread-tianluo的线程处于等待(waiting)状态,持有“0x00000000d61ae3a0”锁,等待“0x00000000d61ae3d0”的锁
5d2f7fe0a4b3a9a369d9732535f195f6.png

实战案例2:jstack 分析CPU过高问题

来个导致CPU过高的demo程序,一个死循环,哈哈~

/*** 有个导致CPU过高程序的demo,死循环*/
public class JstackCase {private static ExecutorService executorService = Executors.newFixedThreadPool(5);public static void main(String[] args) {Task task1 = new Task();Task task2 = new Task();executorService.execute(task1);executorService.execute(task2);}public static Object lock = new Object();static class Task implements Runnable{public void run() {synchronized (lock){long sum = 0L;while (true){sum += 1;}}}}
}

jstack 分析CPU过高步骤

  • 1.top
  • 2.top -Hp pid
  • 3.jstack pid
  • 4.jstack -l [PID] >/tmp/log.txt
  • 5.分析堆栈信息

1.top

在服务器上,我们可以通过top命令查看各个进程的cpu使用情况,它默认是按cpu使用率由高到低排序的

5df0e0b19dcc18696c5636d44264250e.png

由上图中,我们可以找出pid为21340的java进程,它占用了最高的cpu资源,凶手就是它,哈哈!

2. top -Hp pid

通过top -Hp 21340可以查看该进程下,各个线程的cpu使用情况,如下:

2d9ea740f4ca30a0c6ca6e45aad5e6fd.png

可以发现pid为21350的线程,CPU资源占用最高~,嘻嘻,小本本把它记下来,接下来拿jstack给它拍片子~

3. jstack pid

通过top命令定位到cpu占用率较高的线程之后,接着使用jstack pid命令来查看当前java进程的堆栈状态, jstack21350后,内容如下:

b828082b5d79a15ef874de4fcd76efc8.png

4. jstack -l [PID] >/tmp/log.txt

其实,前3个步骤,堆栈信息已经出来啦。但是一般在生成环境,我们可以把这些堆栈信息打到一个文件里,再回头仔细分析哦~

5. 分析堆栈信息

我们把占用cpu资源较高的线程pid(本例子是21350),将该pid转成16进制的值

1c37b00325fe19f92791d11c36391f9d.png

在thread dump中,每个线程都有一个nid,我们找到对应的nid(5366),发现一直在跑(24行)

b828082b5d79a15ef874de4fcd76efc8.png

这个时候,可以去检查代码是否有问题啦~ 当然,也建议隔段时间再执行一次stack命令,再一份获取thread dump,毕竟两次拍片结果(jstack)对比,更准确嘛~

参考与感谢

  • jvm 性能调优工具之 jstack
  • 如何使用jstack分析线程状态
  • Java命令学习系列(二)——Jstack

个人公众号

8d2e7f4a6b8c97b6239351be747e9f67.png
  • 觉得写得好的小伙伴给个点赞+关注啦,谢谢~
  • 如果有写得不正确的地方,麻烦指出,感激不尽。
  • 同时非常期待小伙伴们能够关注我公众号,后面慢慢推出更好的干货~嘻嘻
  • github地址:https://github.com/whx123/JavaHome



推荐阅读
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • 本文将介绍如何编写一些有趣的VBScript脚本,这些脚本可以在朋友之间进行无害的恶作剧。通过简单的代码示例,帮助您了解VBScript的基本语法和功能。 ... [详细]
  • 本文介绍如何通过Windows批处理脚本定期检查并重启Java应用程序,确保其持续稳定运行。脚本每30分钟检查一次,并在需要时重启Java程序。同时,它会将任务结果发送到Redis。 ... [详细]
  • Windows服务与数据库交互问题解析
    本文探讨了在Windows 10(64位)环境下开发的Windows服务,旨在定期向本地MS SQL Server (v.11)插入记录。尽管服务已成功安装并运行,但记录并未正确插入。我们将详细分析可能的原因及解决方案。 ... [详细]
  • 探讨如何通过编程技术实现100个并发连接,解决线程创建顺序问题,并提供高效的并发测试方案。 ... [详细]
  • 本文介绍了如何使用 Spring Boot DevTools 实现应用程序在开发过程中自动重启。这一特性显著提高了开发效率,特别是在集成开发环境(IDE)中工作时,能够提供快速的反馈循环。默认情况下,DevTools 会监控类路径上的文件变化,并根据需要触发应用重启。 ... [详细]
  • 本文详细介绍了如何在Linux系统上安装和配置Smokeping,以实现对网络链路质量的实时监控。通过详细的步骤和必要的依赖包安装,确保用户能够顺利完成部署并优化其网络性能监控。 ... [详细]
  • 本文详细探讨了Java中的24种设计模式及其应用,并介绍了七大面向对象设计原则。通过创建型、结构型和行为型模式的分类,帮助开发者更好地理解和应用这些模式,提升代码质量和可维护性。 ... [详细]
  • PHP 5.2.5 安装与配置指南
    本文详细介绍了 PHP 5.2.5 的安装和配置步骤,帮助开发者解决常见的环境配置问题,特别是上传图片时遇到的错误。通过本教程,您可以顺利搭建并优化 PHP 运行环境。 ... [详细]
  • 深入理解Cookie与Session会话管理
    本文详细介绍了如何通过HTTP响应和请求处理浏览器的Cookie信息,以及如何创建、设置和管理Cookie。同时探讨了会话跟踪技术中的Session机制,解释其原理及应用场景。 ... [详细]
  • CentOS7源码编译安装MySQL5.6
    2019独角兽企业重金招聘Python工程师标准一、先在cmake官网下个最新的cmake源码包cmake官网:https:www.cmake.org如此时最新 ... [详细]
  • 深入理解Java中的volatile、内存屏障与CPU指令
    本文详细探讨了Java中volatile关键字的作用机制,以及其与内存屏障和CPU指令之间的关系。通过具体示例和专业解析,帮助读者更好地理解多线程编程中的同步问题。 ... [详细]
  • 本文介绍了一款用于自动化部署 Linux 服务的 Bash 脚本。该脚本不仅涵盖了基本的文件复制和目录创建,还处理了系统服务的配置和启动,确保在多种 Linux 发行版上都能顺利运行。 ... [详细]
  • 深入解析Spring Cloud Ribbon负载均衡机制
    本文详细介绍了Spring Cloud中的Ribbon组件如何实现服务调用的负载均衡。通过分析其工作原理、源码结构及配置方式,帮助读者理解Ribbon在分布式系统中的重要作用。 ... [详细]
  • 本文详细介绍了如何在Ubuntu系统中下载适用于Intel处理器的64位版本,涵盖了不同Linux发行版对64位架构的不同命名方式,并提供了具体的下载链接和步骤。 ... [详细]
author-avatar
cindy蔡79
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有