获取Java线程转储的常用方法(推荐)

作者:铁锚 时间:2023-05-15 02:30:19 

1. 线程转储简介

线程转储(Thread Dump)就是JVM中所有线程状态信息的一次快照。

线程转储一般使用文本格式, 可以将其保存到文本文件中, 然后人工查看和分析, 或者使用工具/API自动分析。

Java中的线程模型, 直接使用了操作系统的线程调度模型, 只进行简单的封装。

线程调用栈, 也称为方法调用栈。 比如在程序执行过程中, 有一连串的方法调用链:obj1.method2调用了obj2.methodB,obj2.methodB又调用了obj3.methodC。 每个线程的状态都可以通过这种调用栈来表示。

线程转储展示了各个线程的行为, 对于诊断和排查问题非常有用。

下面我们通过具体示例, 来演示各种获取Java线程转储的工具, 以及使用方法。

2. 使用JDK自带的工具

我们一般使用JDK自带的命令行工具来获取Java应用程序的线程转储。 这些工具都在JDK主目录的bin文件夹下。

所以, 只要配置好 PATH 路径即可。 如果不会配置, 可以参考:JDK环境准备

2.1 jstack 工具

jstack 是JDK内置的一款命令行工具, 专门用来查看线程状态, 也可以用来执行线程转储。

一般先通过jps或者ps命令找到Java进程对应的pid, 然后在控制台中通过pid来输出线程转储。 当然, 我们也可以将输出内容重定向到某个文件中。

使用jstack工具获取线程转储的基本参数格式为:


jstack [-F] [-l] [-m] <pid>

下面请看具体的演示:


# 1. 查看帮助信息
jstack -help

输出的内容类似于:


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

对应的参数选项是可选的。 具体含义如下:

  • -F选项, 强制执行线程转储; 有时候jstack pid会假死, 则可以加上-F标志

  • -l选项, 会查找堆内存中拥有的同步器以及资源锁

  • -m选项, 额外打印 native栈帧(C和C++的)

例如, 获取线程转储并将结果输出到文件:


jstack -F 17264 > /tmp/threaddump.txt

使用jps命令可以获取本地Java进程的 pid。

2.2 Java Mission Control

Java Mission Control(JMC)是一款客户端图形界面工具, 用于收集和分析Java应用程序的各种数据。

启动JMC后, 首先会显示本地计算机上运行的Java进程列表。 当然也可以通过JMC连接到远程Java进程。

可以鼠标右键单击对应的进程, 选择 “Start Flight Recording(开始飞行记录)” 。 结束之后, “Threads(线程)” 选项卡会显示“线程转储”:

获取Java线程转储的常用方法(推荐)

2.3 jvisualvm

jvisualvm 是一款客户端图形界面工具, 既简单又实用, 可用来监控 Java应用程序, 对JVM进行故障排查和性能分析。

也可以用来获取线程转储。 鼠标右键单击Java进程, 选择“ Thread Dump”选项, 则可以创建线程转储, 完成后会在新选项卡中自动打开:

获取Java线程转储的常用方法(推荐)

2.4 jcmd

jcmd工具本质上是向目标JVM发送一串命令。 尽管支持很多功能, 但不支持连接远程JVM - 只能在Java进程的本地机器上使用。

其中一个命令是Thread.print, 用来获取线程转储, 示例用法如下:


jcmd 17264 Thread.print

2.5 jconsole

jconsole 工具也可以查看线程栈跟踪。

打开jconsole并连接到正在运行的Java进程, 导航到“线程”选项卡, 可以查看每个线程的堆栈跟踪:

获取Java线程转储的常用方法(推荐)

2.6 小结

事实证明, 可以使用JDK中的很多工具来获取线程转储。 让我们回顾一下, 并总结它们的优缺点:


jstack
jmc
jvisualvm
jcmd
jconsole

3. 使用Linux命令

在企业应用服务器中, 出于安全原因, 可能只安装了 JRE。 这时候没法使用这些JDK内置的工具。

但还是有办法获取线程转储。

3.1 使用kill -3指令

在Unix/Linux之类的系统中, 可以使用kill命令获取线程转储, 底层实现原理, 则是通过系统调用kill()将信号参数发送给进程。 这里需要发送的是-3信号。

一般先通过jps找到JAVA进程对应的pid,kill -3使用示例如下:


kill -3 17264

3.2Ctrl + Break(Windows)

在Windows操作系统的命令行窗口中, 可使用组合键Ctrl + Break来获取线程转储。 当然, 需要先导航至启动Java程序的控制台窗口, 然后同时按下CTRL键和Break键。

需要注意的是, 某些键盘是没有 “Break” 键的。

在这种情况下, 可以组合使用CTRL,SHIFT, 以及Pause键。

这两个命令都可以将线程转储打印到控制台。

4. 通过编程方式使用ThreadMxBean

JMX技术支持各种各样的花式操作。 可通过ThreadMxBean来执行线程转储。

示例代码如下:


private static String threadDump(boolean lockedMonitors, boolean lockedSynchronizers) {

StringBuffer threadDump = new StringBuffer(System.lineSeparator());
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
for(ThreadInfo threadInfo : threadMXBean.dumpAllThreads(lockedMonitors, lockedSynchronizers)) {

threadDump.append(threadInfo.toString());
}
return threadDump.toString();
}

上面代码做的事情很简单, 先通过ManagementFactory获取ThreadMxBean对象。

方法的布尔参数lockedMonitorslockedSynchronizers, 表示是否导出持有的同步器和管程锁。

5. 总结

我们通过具体示例展示了获取线程转储的各种方法。

首先介绍的是各种JDK内置工具,

然后讨论了命令行方式,

最后介绍了JMX编程的方式。

完整的示例代码请参考GitHub仓库。

来源:https://blog.csdn.net/renfufei/article/details/112339222

标签:Java,线程转储
0
投稿

猜你喜欢

  • Android Studio一直处于Building的两种解决方法

    2022-06-13 23:05:22
  • 关于Java虚拟机HotSpot

    2022-10-28 18:36:01
  • Android中TelephonyManager类的方法实例分析

    2021-07-29 10:35:28
  • Flutter使用sqflite处理数据表变更的方法详解

    2023-10-21 11:05:49
  • Java解决约瑟夫问题代码实例

    2023-09-20 19:17:02
  • Fastjson 常用API介绍及下载地址(推荐)

    2023-03-18 23:48:47
  • spring cache注解@Cacheable缓存穿透详解

    2023-12-23 13:41:25
  • springmvc分层领域模型概念详解

    2021-09-07 01:21:51
  • Netty 拆包沾包问题解决方案详解

    2023-09-01 21:58:50
  • java struts2学习笔记之线程安全

    2022-08-07 00:13:07
  • Android自定义view实现有header和footer作为layout使用的滚动控件

    2023-07-31 19:29:54
  • Mybatis-plus foreach拼接字符串查询无数据返回问题

    2022-09-26 17:29:02
  • Java 实战练习之网上电商项目的实现

    2021-07-17 04:23:59
  • android 实现控件左右或上下抖动教程

    2023-03-19 17:02:07
  • Springboot jar主清单属性丢失解决方案

    2022-04-06 05:30:26
  • Android安卓中循环录像并检测内存卡容量

    2021-06-21 13:12:55
  • spring AOP定义AfterThrowing增加处理实例分析

    2021-07-11 14:22:11
  • Java GC 机制与内存分配策略详解

    2022-06-12 05:36:44
  • android开发教程之判断是手机还是平板的方法

    2022-10-22 12:30:41
  • Android 单双击实现的方法步骤

    2023-04-19 02:19:31
  • asp之家 软件编程 m.aspxhome.com