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

获取Java线程id和失控Java线程的堆栈跟踪,java,debugging,jstack,Java,Debugging,Jstack,在我最繁忙的生产安装中,有时我会遇到一个线程,它似乎卡在一个无限循环中。经过大量的研究和调试,我还没有设法找出谁是罪魁祸首,但这似乎是可能的。以下是血淋淋的细节: 当前调试说明: 1) ps-el18975向我展示了Linux pid的问题子线程,19269 $ps -eL | grep 18975 ... PID LWP TTY TIME CMD 18975 18994 ? 00:00:05 java 18975 19268 ? 00:00

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

当前调试说明:

1) ps-el18975向我展示了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-l18975说没有死锁,jstack-m18975不起作用

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

对象中的“http-342.877.573.944-8080-360”守护进程prio=10 tid=0x0000002adaba9c00 nid=0x754c.wait()[0x00000000595bc000..0x00000000595bcb0] java.lang.Thread.State:正在等待(在对象监视器上) 在java.lang.Object.wait(本机方法) -等待(org.apache.tomcat.util.net.JIoEndpoint$Worker) 等待(Object.java:485) 位于org.apache.tomcat.util.net.JIoEndpoint$Worker.await(JIoEndpoint.java:416) -锁定(org.apache.tomcat.util.net.JIoEndpoint$Worker) 位于org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:442) 运行(Thread.java:619) 4) ps-eL输出的线程ID与jstack的输出不匹配,或者至少我看不到它。(jstack文档有点稀疏。)

5) 没有大量IO、内存使用或其他相应的活动线索可供处理

平台:

  • 爪哇6
  • 雄猫6
  • RHEL 4(64位)
有人知道我如何从LinuxPS输出连接到有问题的子java线程吗?非常接近,但到目前为止…

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

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

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


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

从内存中,如果在控制台上按住CTRL-BREAK键,您将获得当前线程的转储和一些堆栈跟踪帧

从内存(我不确定这是IntelliJ IDEa功能,还是java中的默认功能),但它会告诉您哪个线程处于死锁状态,以及它们正在等待哪个对象。您应该能够将输出重定向到一个文件,只需grep就可以找到死锁的文本


JConsole、VisualVM或其他探查器(如JProfiler)也将向您显示线程及其堆栈,但是如果您不想使用任何外部工具,我认为CTRL-BREAK将为您提供所需的工具。

看起来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;
}
#/usr/bin/perl-w
而(){
if(/nid=(0x[:xdigit:]+)/){
$lwp=十六进制($1);
s/nid=/lwp=$lwp nid=/;
}
印刷品;
}
在阳光下 请注意,
prstat
默认情况下显示轻量级进程的数量,而不是LWPID

要查看特定用户的所有轻量级进程的信息,请使用
-L
选项

prstat -L -v -u weblogic
现在使用LWPID并将其转换为十六进制,并将其与线程转储中的nid进行匹配

对于Linux,使用ps-efL,-L选项将显示LWP。 作为旁注,
“http-342.877.573.944-8080-360”守护进程prio=10表示
“ThreadName(由JVM提供)”运行模式(从pid继承)优先级(从pid继承)

但我无法从jconsole中判断哪个线程是问题所在:(有超过400个线程,ps输出非常有用,我应该能够做出权威性的分析。+1对于jconsole.Jstack听起来不受支持:“注意-此实用程序不受支持,在未来版本的J2SE SDK中可能不可用。jstack当前在Windows平台或Linux Itanium平台上不可用。”(很抱歉删除和重新发布。)嗯…好的,有点麻烦,最好在凌晨2点完成,但我看到您的逻辑…可能会工作…仅仅因为不支持jstack并不意味着它不是一个有效的调试工具。visualvm有一个过滤器,用于“仅显示实时线程”“这可能对你有帮助。虽然我在一年前尝试过,但没有成功,但现在它对我有效。我正在使用Java的新版本,所以可能就是它。或者我只是制作了一个
hexNid2dec(pid)
math error。或者可能是在做其他不可思议的蠢事。请记住,'nid'是'native id'——Java线程的底层系统本机标识符。@Cowan本机id是什么?pid还是lwpid?根据这篇文章:它应该是pid,但这个答案表明它是lwpid。作为一行:
jstack | perl-ne'if(/nid=(0x[[:xdigit:]+)/){$lwp=hex($1);s/nid=/lwp=$lwp-nid=/;}print;'
prstat -L -v -u weblogic