我如何在 UNIX 或 Windows 上抓取 JVM 中的线程转储?

线程转储是 Java 虚拟机 (JVM) 中当前处于活动状态的所有 Java 线程的列表。

可使用多种方式抓取 JVM 中的线程转储。我们强烈建议抓取一个以上的线程转储。最好是按一定的时间间隔来抓取 10 个线程转储(例如,每十秒钟抓取一个线程转储)。

步骤 1:获取 Java 进程的 PID

为了能够获取线程转储,您将需要的第一条信息是 Java 进程的 PID。

Java JDK 在推出时提供 jps 命令,它可列出所有 Java 进程 ID。您可以按以下形式运行此命令:

jps -l 70660 sun.tools.jps.Jps 70305

注意:在 Linux 和 UNIX 中,您可能需要以 sudo -u user jps -l 的形式运行此命令,其中,“user”是作为 Java 进程运行方的用户的用户名。

如果它不起作用,或者您仍然无法找到 Java 进程(未设置路径、未安装 JDK 或 Java 版本较老),请使用

  • UNIX、Linux 和 Mac OS X:ps -el | grep java
  • Windows:按 Ctrl+Shift+Esc 打开任务管理器,并找到 Java 进程的 PID

步骤 2:请求 JVM 中的线程转储

jstack

如果已安装/可用,我们建议使用 jstack 工具。它会将线程转储打印到命令行控制台。

要使用 jstack 获取线程转储,请运行以下命令:
jstack -l <pid>

要将连续的线程转储输出到一个文件,您可使用以下控制台输出重定向/附加指令:
jstack -l <pid> >> threaddumps.log

注意:

  • jstack 工具从 JDK 1.5 开始可用(对于 Windows 上的 JVM,它仅在 JDK 1.5 和 JDK 1.6 的部分版本中可用)。
  • jstack 甚至可在启用了 -Xrs jvm 参数的情况下正常工作
  • 您无法使用 JDK 1.6 中的 jstack 工具抓取在 JDK 1.5 上运行的进程中的线程转储。
  • 在 Linux 和 UNIX 中,您需要以拥有 Java 进程的用户身份运行命令:
    sudo -u <java-user> jstack -l <pid>
    (<java-user> 应替换为运行 Java 进程的用户的 ID)
  • 在 Windows 中,如果您在运行 jstack 时遇到错误“存储空间不足,无法处理此命令”,则您必须以 Windows 系统用户的身份或拥有 Java 进程的用户身份运行 jstack。为此,您可以使用在此处下载的 psexec。要以系统用户的身份运行 jstack,请使用如下命令:
    psexec -s jstack <pid>  >> threaddumps.log
    如果您无法在服务器上安装 psexec,则可以创建包含该命令的 .bat 文件,然后使用 Windows 任务调度程序(以其他用户身份)运行该文件。
  • 有时需要在 64 位系统上添加 -J-d64 选项,例如:
    jstack -J-d64 -l <pid> >> threaddumps.log

jstack 脚本

以下是一个脚本,它来自将使用 jstack 抓取一系列线程转储的 eclipse.org。此外,它也将使用 top 命令获取线程级别的 CPU 使用情况。

#!/bin/bash
if [ $# -eq 0 ]; then
    echo >&2 "Usage: jstackSeries <pid> <run_user> [ <count> [ <delay> ] ]"
    echo >&2 "    Defaults: count = 10, delay = 0.5 (seconds)"
    exit 1
fi
pid=$1          # required
user=$2         # required
count=${3:-10}  # defaults to 10 times
delay=${4:-0.5} # defaults to 0.5 seconds
while [ $count -gt 0 ]
do
    sudo -u $user top -H -b -n1 -p $pid >top.$pid.$(date +%H%M%S.%N) &
    sudo -u $user jstack -l $pid >jstack.$pid.$(date +%H%M%S.%N)
    sleep $delay
    let count--
    echo -n "."
done

 

其运行方式如下:
sh jstackSeries.sh [pid] [cq5serveruser] [count] [delay]

例如:
sh jstackSeries.sh 1234 cq5serveruser 10 3

  • 1234 是 Java 进程的 PID
  • cq5serveruser 是作为 Java 进程运行方的 Linux 或 UNIX 用户
  • 10 是要抓取的线程转储的数量
  • 3 是每个转储之间的延迟

注意:top 输出具有十进制格式的本机线程 ID,而 jstack 输出具有十六进制的 nid。通过将线程 ID 转换为十六进制,可以将 top 输出的高 cpu 线程与 jstack 输出相匹配。

适用于 Adobe Experience Manager 的线程转储工具

如果您正在使用 Adobe Experience Manager 产品,则可以安装此工具,以获取一个用于生成线程转储的简单 UI。

获取线程转储的替代方法

如果 jstack 工具不可用,则您可以按以下方式抓取线程转储:

注意:如果启用了命令行参数 -Xrs,某些工具无法抓取 JVM 中的线程转储。如果您在抓取线程转储时遇到问题,请检查此选项是否已启用。

UNIX、Mac OS X 和 Linux(JDK 1.4 或更低版本)

在 UNIX、Mac OS X 和 Linux 中,您可以向 Java 进程发送一个 QUIT 信号,以告知它将线程转储输出为标准输出。

  1. 为此,请运行以下命令:
    kill -QUIT <pid>
    您可能需要以 sudo -u user kill -QUIT <pid> 的形式运行此命令,其中,“user”是作为 Java 进程运行方的用户。
  2. 如果您要使用 crx-quickstart/server/start 脚本启动 CQSE,则您的线程转储将被输出到 crx-quickstart/server/logs/startup.log。如果您使用 JBoss、WebSphere、Tomcat 等之类的第三方应用程序服务器,请参阅服务器的文档,以了解标准输出将被定向到哪个文件。
Windows:
JDK 1.X
  1. 下载 javadump.exe(附在下面)。
  2. 通过以下三个参数启动 JVM(必须按照正确的顺序):
    -XX:+UnlockDiagnosticVMOptions -XX:+LogVMOutput -XX:LogFile=C: mpjvmoutput.log
  3. 按 Ctrl+Shift+Esc 打开任务管理器。
  4. 找到 Java 进程的 PID。
  5. 在命令行中,运行
    javadump.exe [pid]
  6. 线程转储将在步骤 2 中提到的 jvmoutput.log 文件内显示。
JDK 1.6

要通过 jconsole 工具获取线程转储,请使用以下插件:[0]

以下是如何请求线程转储的步骤:

  1. 将以下参数添加到运行公报的 JVM:-Dcom.sun.management.jmxremote
  2. 下载并安装 JDK1.6(如果尚未完成)。
  3. 下载并提取线程转储分析器实用程序。[1]
  4. 运行 JDK 1.6 的 jconsole.exe
                                jconsole.exe -pluginpath /path/to/file/tda.jar
  5. 单击线程转储选项卡。
  6. 单击请求线程转储链接。

注意:如果您运行的是 CQ 5 和/或 CRX(含 Sling),并希望观察正在运行的线程,则可以请求 http://<host>:<port>/system/console/threads 以获取线程列表。但请注意,这些线程转储不适合使用 Samurai 或 TDA 之类的线程转储分析工具。

适用于

在 JVM 中运行的所有 Adobe 产品

[0] http://technet.microsoft.com/zh-cn/sysinternals/bb897553.aspx
[1] https://github.com/irockel/tda
[2] http://docs.day.com/cn/home/docutools/javadump_exe.html

下载

本产品经 Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License 许可  Twitter™ 与 Facebook 中的内容不在 Creative Commons 的条款约束之下。

法律声明   |   在线隐私策略