kill -3 获取java线程转储

Posted

技术标签:

【中文标题】kill -3 获取java线程转储【英文标题】:kill -3 to get java thread dump 【发布时间】:2011-06-20 01:30:05 【问题描述】:

我正在使用kill -3 命令在 unix 中查看 JVM 的线程转储。但是我在哪里可以找到这个kill 命令的输出?我迷路了!!

【问题讨论】:

你要杀死哪个进程?它是 J2EE 应用服务器吗?如果是这种情况,您应该在标准输出中找到堆栈跟踪。 我正在杀死一个运行 java 类的进程 不应该在控制台上写线程转储。因为java类有控制台作为标准输出 【参考方案1】:

您也可以使用 jstack(包含在 JDK 中)进行线程转储并将输出写入您想要的任何位置。这在 unix 环境中不可用吗?

jstack PID > outfile

【讨论】:

是的 - 在它运行的时间点。您还可以为打印附加锁定信息的长列表指定 -l(小写 L) 直到 jstack 命令由于“无法从地址推断线程类型”而持续失败;-( 如果您看到该错误,建议您与供应商联系。快速搜索显示,例如,RHEL 中有一个关于此错误和 openjdk 的开放错误... 值得注意的是jstack需要JDK。如果您在仅安装了 JRE 的服务器上运行应用程序,则需要找到另一种线程转储方法。 这里是如何使用 jstack 来获取在不同用户下运行的进程的线程转储,例如 windows 服务:***.com/questions/1197912/…【参考方案2】:

线程转储从您执行kill -3 的VM 写入系统。如果您将 JVM 的控制台输出重定向到文件,则线程转储将在该文件中。如果 JVM 在打开的控制台中运行,则线程转储将显示在其控制台中。

【讨论】:

有一种方法可以将 JVM 线程转储输出重定向到单独的文件。请参阅我的回答。【参考方案3】:

有一种方法可以将中断信号上的 JVM 线程转储输出重定向到带有 LogVMOutput diagnostic option 的单独文件:

-XX:+UnlockDiagnosticVMOptions -XX:+LogVMOutput -XX:LogFile=jvm.log

【讨论】:

从技术上讲,这不会“重定向”线程转储输出。它打开 JVM 日志记录到 jvm.log (包括线程转储输出),但 kill -QUIT 仍将转储到进程的标准输出(以及)。赞成对晦涩的 JVM 选项的描述:)【参考方案4】:

在 Java 8 中,jcmd 是首选方法。

jcmd <PID> Thread.print

下面是来自Oracle documentation的sn-p:

JDK 8 的发布引入了 Java Mission Control、Java Flight Recorder 和 jcmd 实用程序,用于诊断 JVM 和 Java 应用程序的问题。 建议使用最新的实用程序 jcmd 而不是以前的 jstack 实用程序,以增强诊断并降低性能开销。

但是,将其与应用程序一起提供可能会涉及许可问题,我不确定。

【讨论】:

不幸的是jcmd 无法使用com.sun.tools.attach.AttachNotSupportedException: Insufficient memory or insufficient privileges to attach 连接到Windows 服务进程,而jstack -F 成功:***.com/questions/1197912/… 您需要在与 java 进程相同的用户下运行 jcmd Thread.dump,否则您的连接将被丢弃。见***.com/questions/25438983/…【参考方案5】:

在放置 JVM 标准输出的同一位置。如果您有 Tomcat 服务器,这将是 catalina_(date).out 文件。

【讨论】:

【参考方案6】:

当使用 kill -3 时,应该会在标准输出中看到线程转储。大多数应用程序服务器将标准输出写入单独的文件。你应该在使用 kill -3 时找到它。有多种获取线程转储的方法:

kill -3 &lt;PID&gt;:将输出提供给标准输出。 如果可以访问运行服务器的控制台窗口,则可以使用 Ctrl+Break 组合键在 STDOUT 上生成堆栈跟踪。

对于热点虚拟机,我们还可以使用jstack 命令生成线程转储。它是 JDK 的一部分。语法如下:

Usage:

jstack [-l] <pid> (to connect to running process)
jstack -F [-m] [-l] <pid>(to connect to a hung process)

 - For JRockit JVM we can use JRCMD command which comes with JDK Syntax: 
   jrcmd <jrockit pid> [<command> [<arguments>]] [-l] [-f file] [-p] -h]

【讨论】:

我在使用 Kill -3 时遇到问题。它工作正常,但在将线程转储写入控制台后也会终止进程。它应该这样做吗? @Ashley - 不,kill -3 &lt;PID&gt; 不应该杀死 JVM。您在看什么类型的 Java 应用程序?【参考方案7】:

在 Jboss 中你可以执行以下操作

nohup $JBOSS_HOME/bin/run.sh -c  yourinstancename $JBOSS_OPTS >> console-$(date +%Y%m%d).out  2>&1 < /dev/null &
kill -3 <java_pid>

这会将您的输出/线程转储重定向到上述命令中指定的文件控制台。

【讨论】:

【参考方案8】:
    查找进程 ID [PS ID] 执行 jcmd [PS ID] Thread.print

【讨论】:

【参考方案9】:

如果您想要独立 Java 进程的线程转储,您应该遵循的步骤

第 1 步:获取调用 java 程序的 shell 脚本的进程 ID

linux$ ps -aef | grep "runABCD"

user1  **8535**  4369   0   Mar 25 ?           0:00 /bin/csh /home/user1/runABCD.sh

user1 17796 17372   0 08:15:41 pts/49      0:00 grep runABCD

步骤 2: 获取由 runABCD 调用的子进程 ID。使用上面的 PID 来获取孩子。

linux$ ps -aef | grep **8535**

user1  **8536**  8535   0   Mar 25 ?         126:38 /apps/java/jdk/sun4/SunOS5/1.6.0_16/bin/java -cp /home/user1/XYZServer

user1  8535  4369   0   Mar 25 ?           0:00 /bin/csh /home/user1/runABCD.sh

user1 17977 17372   0 08:15:49 pts/49      0:00 grep 8535

第 3 步: 获取特定进程的 JSTACK。获取 XYSServer 进程的进程 ID。即 8536

linux$ jstack **8536** > threadDump.log

【讨论】:

以上是关于kill -3 获取java线程转储的主要内容,如果未能解决你的问题,请参考以下文章

无法获取线程转储?任何想法为啥我的应用程序阻塞?

Java中如何获取到线程dump文件

Java 中怎么获取一份线程 dump 文件?

Java 以编程方式强制线程转储 - 如“jstack -F -l <​​PID>”

C# kill线程正常释放资源?

线程转储分析