获取 Java 线程 ID 和失控 Java 线程的堆栈跟踪

2022-09-03 01:46:44

在我最繁忙的生产安装中,有时我会遇到一个似乎陷入无限循环的线程。经过大量的研究和调试,我还没有设法弄清楚谁是罪魁祸首,但似乎这应该是可能的。以下是血腥的细节:

当前调试说明:

1) ps -eL 18975 向我展示了 Linux pid 的问题子线程,19269

$ps -eL | grep 18975
...
PID   LWP   TTY          TIME CMD
18975 18994 ?        00:00:05 java
18975 19268 ?        00:00:00 java
18975 19269 ?        05:16:49 java
18975 19271 ?        00:01:22 java
18975 19273 ?        00:00:00 java
...

2) jstack -l 18975 表示没有死锁,jstack -m 18975 不起作用

3) jstack -l 18975 确实为我的所有线程 (~400) 提供了堆栈跟踪。示例线程堆栈(不是问题):

"http-342.877.573.944-8080-360" daemon prio=10 tid=0x0000002adaba9c00 nid=0x754c in Object.wait() [0x00000000595bc000..0x00000000595bccb0]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on  (a org.apache.tomcat.util.net.JIoEndpoint$Worker)
        at java.lang.Object.wait(Object.java:485)
        at org.apache.tomcat.util.net.JIoEndpoint$Worker.await(JIoEndpoint.java:416)
        - locked  (a org.apache.tomcat.util.net.JIoEndpoint$Worker)
        at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:442)
        at java.lang.Thread.run(Thread.java:619)

4)ps -eL输出的线程ID与jstack的输出不匹配,或者至少我看不到它。(jstack 文档有点稀疏。

5)没有繁重的IO,内存使用或其他相应的活动线索可以使用。

平台:

  • 爪哇 6
  • 雄猫 6
  • RHEL 4(64 位)

有谁知道我如何从linux ps输出到我的问题子java线程建立连接?如此之近,又如此之远...


答案 1

看起来jstack输出中的nid是Linux LWP id。

"http-342.877.573.944-8080-360" daemon prio=10 tid=0x0000002adaba9c00 nid=0x754c in Object.wait() [0x00000000595bc000..0x00000000595bccb0]

将 nid 转换为十进制,您就拥有了 LWP ID。在你的情况下,0x754c是30028。此过程未显示在我们的 ps 输出中,但它可能是您为节省空间而省略的 LWP 之一。

下面是一个 Perl 代码段,可用于通过管道将 jstack 的输出传递到:

#!/usr/bin/perl -w
while (<>) {
    if (/nid=(0x[[:xdigit:]]+)/) {
        $lwp = hex($1);
        s/nid=/lwp=$lwp nid=/;
    }
    print;
}

答案 2

您可以使用 JConsole 查看线程的堆栈跟踪。

如果您使用的是 JDK 1.6.0_07 或更高版本,则还可以使用 visualvm

这两个工具都提供了应用程序中所有正在运行的线程的良好视图。visualvm 要好得多,但希望看到所有线程都可以帮助您跟踪失控的线程。

检查始终处于“正在运行”状态的线程。当我们有一个失控的线程时,堆栈跟踪会不断变化。因此,我们能够分辨出循环正在调用哪些方法,并跟踪循环。