Thread dumps
(线程转储)能帮助我们判断 CPU 峰值、死锁、内存异常、应用反应迟钝、响应时间变长和其他系统问题。一些在线的分析工具比如 http://fastthread.io/ 也能帮助我们分析和定位问题,但是这些工具都要求有一个 dump 文件。因此在这篇文章当中,我总结了7中抓取 Java Thread Dumps 文件的方式。
Thread dump
文件主要保存的是java应用中各线程在某一时刻的运行的位置,即执行到哪一个类的哪一个方法哪一个行上。thread dump
是一个文本文件,打开后可以看到每一个线程的执行栈,以stacktrace
的方式显示。通过对thread dump
的分析可以得到应用是否“卡”在某一点上,即在某一点运行的时间太长,如数据库查询,长期得不到响应,最终导致系统崩溃。单个的thread dump
文件一般来说是没有什么用处的,因为它只是记录了某一个绝对时间点的情况。比较有用的是,线程在一个时间段内的执行情况。
1. jstack
jstack
是一个抓取 thread dump
文件的有效的命令行工具,它位于 JDK 目录里的 bin 文件夹下(JDK_HOME\bin),以下是抓取 dump 文件的命令:
jstack -l <pid> > <file-path>
说明:
pid: Java 应用的进程 id ,也就是需要抓取 dump 文件的应用进程 id。
file-path: 保存 dump 文件的路径。
示例:
jstack -l 37320 > /opt/tmp/threadDump.txt
上面的例子演示了用 jstack 生成 dump 文件到 /opt/tmp/threadDump.txt
目录下。
从 Java5 开始,jstack 被包含进了 jdk 当中,如果你使用老版本的 jdk,要考虑使用其他方式。
eg.
2. Kill -3
处于安全方面的考虑,有一部分生产环境的机器只包含 JRE 环境,因此就不能使用 jstack 工具了,在这种情况下,我们可以使用 kill -3
的方式:
kill -3 <pid>
说明:
- pid: Java 应用的进程 id ,也就是需要抓取 dump 文件的应用进程 id 。
示例:
kill -3 37320
当使用 kill -3
生成 dump 文件时,dump 文件会被输出到标准错误流。假如你的应用运行在 tomcat 上,dump 内容将被发送到<TOMCAT_HOME>/logs/catalina.out
文件里。
3. JVisualVM
Java VisualVM 是一个可以提供 JVM 信息的图形界面工具。它位于 JDK_HOME\bin\jvisualvm.exe
文件里。从 JDK6 Update7 开始,它被包含进 JDK 里。
运行 jvisualvm,在左侧面板中(如下图所示),列出了运行的 JVM 信息,这个工具可以从本地或者远程运行的 JVM 里抓取 dump 文件。
点击上图的进程名称对应的 Thread Dump
按钮,将会生成 dump 文件,如下图所示:
4. JMC
Java Mission Control (JMC) 是一个能从本地或生产环境中收集和分析数据的工具,从 Oracle JDK 7 Update 40 开始,它被包含进 JDK 里,它可以从 JVM 里生成 dump 文件。JMC 位于 JDK_HOME\bin\jmc.exe
文件里:
运行该工具之后,你可以看到运行在本地的 Java 进程,它也可以连接到远程机器。双击你想要生成 dump 文件的 Java 进程,点击Flight Recorder
,你会看到以下的对话框:
在 Thread Dump
下拉框,你可以选择生成 dump 文件的时间间隔。在上面的例子里,每隔60秒将会生成一个 dump 文件。选择完成之后启动 Flight recorder ,可以在 Threads 面板看到 dump 文件的内容:
5. Windows (Ctrl + Break)
这种方式仅仅在 Windows 操作系统上有效:
在控制台窗口上选中命令行
在命令行窗口上按 “Ctrl + Break” 命令
然后会生成 dump 文件,dump 文件的内容会被打印在命令行窗口上。
注意1: 有几款笔记本(比如 Lenovo T 系列)已经取消了 “Break” 键,在这种情况下你不得不用谷歌搜索与 Break 键功能类似的键,我发现 “Function key + B” 键与 Break 键的功能相同,因此我用 “Ctrl + Fn + B” 键来生成 dump 文件。
注意2: 用上述方式有一个缺点就是 dump 文件的内容会被打印到控制台上,没有 dump 文件的话,我们很难用分析工具比如http://fasthread.io来分析 dump 文件。因此你可以使用以下命令将 dump 文件的内容输出到文本文件当中,比如你的应用程序名字叫 SampleThreadProgram ,那么通常使用的命令如下:
java -classpath . SampleThreadProgram
将 dump 文件的内容输出到文本文件的命令如下:
java -classpath . SampleThreadProgram > C:\workspace\threadDump.txt 2>&1
当你按下 “Ctrl + Break” 键之后,dump 文件会被保存到 C:\workspace\threadDump.txt 里。
6. ThreadMXBean
从 JDK 1.5 开始,ThreadMXBean 被引入。这是 JVM 的管理接口,使用这个接口你仅需要少量的代码就能生成 dump 文件,以下是使用 ThreadMXBean 生成 dump 文件的主要实现:
public void dumpThreadDump() {
ThreadMXBean threadMxBean = ManagementFactory.getThreadMXBean();
for (ThreadInfo ti : threadMxBean.dumpAllThreads(true, true)) {
System.out.print(ti.toString());
}
}
7. APM Tool – App Dynamics
一些应用性能监控工具提供了生成 dump 文件的功能,如果你使用 App Dynamics 监控你的应用,以下就是生成 dump 文件的步骤:
打开创建动作窗口,在创建动作窗口中选择 Diagnostics->Take a thread dump;
输入动作名称、抓取 dump 文件的数量、抓取 dump 文件的时间间隔(毫秒);
如果你想在抓取 dump 动作开始之前执行一些操作,那么你可以选中
Require approval executing before this Action
这个复选框,然后输入个人或小组的 email 地址;点击 OK.
8. jcmd命令也可以抓取
The jcmd tool was introduced with Oracle’s Java 7. It’s useful in troubleshooting issues with JVM applications. It has various capabilities such as identifying java process Ids, acquiring heap dumps, acquiring thread dumps, acquiring garbage collection statistics, ….
Using the below JCMD command you can generate thread
jcmd <pid> Thread.print > <file-path>
where
pid: is the Process Id of the application, whose thread dump should be captured
file-path: is the file path where thread dump will be written in to.
Example:
jcmd 37320 Thread.print > /opt/tmp/threadDump.txt
As per the example thread dump of the process would be generated in /opt/tmp/threadDump.txt file.
eg.
9. Linux查看java进程耗CPU比较高的问题,常用命令和步骤:
1)用 top 看看是否 java 进程占用 CPU 高,如果是 ,执行命令 top -p pid -H (记得替换 pid)
2)抓 dump 发回来
PID=xxxxxx
DATE_DIR=`date "+%Y%m%d%H%M"`
mkdir $DATE_DIR
jstack $PID > $DATE_DIR/jstack-$PID.dump 2>&1
jinfo $PID > $DATE_DIR/jinfo-$PID.dump 2>&1
jstat -gcutil $PID > $DATE_DIR/jstat-gcutil-$PID.dump 2>&1
jstat -gccapacity $PID > $DATE_DIR/jstat-gccapacity-$PID.dump 2>&1
jmap $PID > $DATE_DIR/jmap-$PID.dump 2>&1
jmap -heap $PID > $DATE_DIR/jmap-heap-$PID.dump 2>&1
jmap -histo $PID > $DATE_DIR/jmap-histo-$PID.dump 2>&1
总结
尽管我在前面列出了7种抓取 dump 文件的方式,但恕我直言,jstack
和 kill -3
是最好的选择,原因如下:
a. 简单,容易实现;
b. 通用:在大多数情况下,不管操作系统类型、Java 厂商、JVM 版本等等。
https://dzone.com/articles/how-to-take-thread-dumps-7-options