2011-11-08 46 views
11

我在构建服务器上存在间歇性问题,构建中的某个Java进程无法终止,并且似乎永远持续运行(使用100%的CPU)(我已经看到它在整个周末运行了2天以上通常需要大约10分钟)。似乎是阻止这一进程的唯一途径。这个Java进程为什么没有终止?

我已经试过在进程上调用kill -QUIT pid,但它似乎没有产生任何堆栈跟踪到STDOUT(也许它没有响应信号?)。没有-F强制选项的jstack似乎无法连接到正在运行的JVM,但使用强制选项时,它确实会生成下面的输出。

不幸的是,即使有堆栈跟踪,我也看不到有任何明显的路径需要进一步调查。

据我可以告诉它显示两个运行Object.wait的'BLOCKED'线程(它们的堆栈似乎只包含核心Java代码,没有我们的),第三个是'IN_VM'没有堆栈输出。

我应该采取什么措施来收集有关问题原因的更多信息(或者更好,但我该如何解决问题)?

 
$ /opt/jdk1.6.0_29/bin/jstack -l -F 5546 
Attaching to process ID 5546, please wait... 
Debugger attached successfully. 
Server compiler detected. 
JVM version is 20.4-b02 
Deadlock Detection: 

No deadlocks found. 

Finding object size using Printezis bits and skipping over... 
Thread 5555: (state = BLOCKED) 

Locked ownable synchronizers: 
    - None 

Thread 5554: (state = BLOCKED) 
- java.lang.Object.wait(long) @bci=0 (Interpreted frame) 
- java.lang.ref.ReferenceQueue.remove(long) @bci=44, line=118 (Interpreted frame) 
- java.lang.ref.ReferenceQueue.remove() @bci=2, line=134 (Interpreted frame) 
- java.lang.ref.Finalizer$FinalizerThread.run() @bci=3, line=159 (Interpreted frame) 

Locked ownable synchronizers: 
    - None 

Thread 5553: (state = BLOCKED) 
- java.lang.Object.wait(long) @bci=0 (Interpreted frame) 
- java.lang.Object.wait() @bci=2, line=485 (Interpreted frame) 
- java.lang.ref.Reference$ReferenceHandler.run() @bci=46, line=116 (Interpreted frame) 

Locked ownable synchronizers: 
    - None 

Thread 5548: (state = IN_VM) 

Locked ownable synchronizers: 
    - None 

(Java版本1.6.0更新29,科学运行Linux 6.0版)

更新:

运行strace -f -p 894产生的一个看似层出不穷......

[pid 900] sched_yield()    = 0 
[pid 900] sched_yield()    = 0 
... 

然后当Ctrl-Cd

Process 894 detached 
... 
Process 900 detached 
... 
Process 909 detached 

jmap -histo 894没有连接,但jmap -F -histo 894回报......

 
Attaching to process ID 894, please wait... 
Debugger attached successfully. 
Server compiler detected. 
JVM version is 20.4-b02 
Iterating over heap. This may take a while... 
Finding object size using Printezis bits and skipping over... 
Finding object size using Printezis bits and skipping over... 
Object Histogram: 

num  #instances #bytes Class description 
-------------------------------------------------------------------------- 
1:  11356 1551744 * MethodKlass 
2:  11356 1435944 * ConstMethodKlass 
3:  914 973488 * ConstantPoolKlass 
4:  6717 849032 char[] 
5:  16987 820072 * SymbolKlass 
6:  2305 686048 byte[] 
7:  914 672792 * InstanceKlassKlass 
8:  857 650312 * ConstantPoolCacheKlass 
9:  5243 167776 java.lang.String 
10:  1046 108784 java.lang.Class 
11:  1400 87576 short[] 
12:  1556 84040 * System ObjArray 
13:  1037 64584 int[] 
14:  103 60152 * ObjArrayKlassKlass 
15:  622 54736 java.lang.reflect.Method 
16:  1102 49760 java.lang.Object[] 
17:  937 37480 java.util.TreeMap$Entry 
18:  332 27960 java.util.HashMap$Entry[] 
19:  579 27792 java.nio.HeapByteBuffer 
20:  578 27744 java.nio.HeapCharBuffer 
21:  1021 24504 java.lang.StringBuilder 
22:  1158 24176 java.lang.Class[] 
23:  721 23072 java.util.HashMap$Entry 
24:  434 20832 java.util.TreeMap 
25:  689 18936 java.lang.String[] 
26:  238 17440 java.lang.reflect.Method[] 
27:  29 16800 * MethodDataKlass 
28:  204 14688 java.lang.reflect.Field 
29:  330 13200 java.util.LinkedHashMap$Entry 
30:  264 12672 java.util.HashMap 
... 
585:  1 16 java.util.LinkedHashSet 
586:  1 16 sun.rmi.runtime.NewThreadAction$2 
587:  1 16 java.util.Hashtable$EmptyIterator 
588:  1 16 java.util.Collections$EmptySet 
Total :  79700 8894800 
Heap traversal took 1.288 seconds. 
+0

您可以尝试在运行服务器的控制台上按[CTRL] + [SYSREQ]。这会给你一个线程转储,它会像获取的那样冗长。 – JimmyB

回答

1

螺纹5554可能表明你有很多与finalize方法,对象,和/或某些问题有finalize方法。看这个可能是值得的。

我对jstack并不熟悉,但它看起来像输出的信息更少,我更熟悉的线程转储。尝试获取线程转储可能很有用:kill -QUIT java_pid。请注意,转储转到标准输出可能是控制台或记录文件,具体取决于您的设置。

如果很难确定标准输出指向哪里,并且假定它正在进入一个文件,那么在最近的修改时间内可以使用find来标识候选文件。这暗示了在注释this blog post

你可以运行在您的根目录中找到[2]命令,并找出 在过去x秒改变。我通常使用find来帮助我 访问最近10分钟内发生更改的所有日志,例如:find /var/tomcat -mmin -3 -print(打印出所有在 /var/tomcat下修改的文件最后3分钟)。

请注意,如果您正在使用-Xrs运行的JVM,这意味着SIGQUIT信号处理程序将不会被安装,您将无法使用请求线程转储的意思。

+0

5554是终结者,应该停放,除非有确定的东西。它不应该阻止这个过程终止。杀-QUIT是一个非常好的主意,因为它可以帮助你弄清楚5555是怎么回事,看起来更可能是罪魁祸首。 – philwb

+0

下次发生问题时,我会尝试'kill -QUIT'并查看是否提供了更多信息,谢谢。 我想可能会有一些自定义的finalisers,但他们应该做的只是关闭打开的文件。我想这是快速和相当安全的,但也许不是... –

+0

我认为@philwb将是正确的。终结者可能没有错 - 终结者线程正在等待某事做,而不是在工作时被阻塞。 – sudocode

2

这可能是由内存不足也引起。我要做两件事情:

  • 由addingJVM内存不足启用自动堆转储参数

    -XX:+ HeapDumpOnOutOfMemoryError XX:HeapDumpPath =/tmp目录

  • 尝试连接到与您的JConsole JVM并看看是否有任何不寻常的模式

+0

不幸的是,jconsole似乎没有连接到它(如果我远程尝试,只是超时,如果我从服务器运行它,相关的PID在列表中灰显)。我将看看我可以做些什么来将这些参数传递给正确的JVM调用。 –

2

我会怀疑内存问题。您可能需要使用jstat观察进程,并在需要杀死进程的时间周围使用jmap进行堆转储。查看jstat是否指示连续的GC。另外,您可能需要检查一般系统的运行状况(打开文件描述符,网络等)。记忆将是最简单的,所以我强烈建议从它开始。

+0

不幸的是,jstat给了我'无法与目标同步'的消息。 jmap似乎能够产生一些信息(我会更新上面的问题)。 –

+0

除了上面的直方图之外,我似乎可以用'jmap -F -dump:format = b,file = heap.bin 894'获得一堆堆,但我还不确定如何处理它。 –

+0

你可以使用eclipse MAT来查看堆转储。寻找泄漏嫌疑人。然而,很奇怪你无法使用jstat。你使用了什么命令? – aishwarya

3

您总是可以通过strace -f -p pid来查看Java进程正在做什么。从它的外观(你不能让一个jstack没有-F和螺纹5548显示没有调用堆栈,并IN_VM),它看起来像螺纹5548正在做过多的东西,或者可能是在某些无限循环。

+0

正在运行'strace -f -p 894'我收到了一堆说''pid 900] sched_yield()= 0'的线......有趣... –

+0

@MattSheppard:从这一点来说,我会遵循bestsss的建议,得到一些回溯。如果你的系统有'pstack',只需执行'pstack '。否则,你必须执行'gdb/path/to/java ',并从gdb'bt'和'quit'执行。 – ninjalj

+0

我会在下次发生时尝试。 –

1

我遇到了类似的问题,我的JBOSS jvm得到了一个无限循环,最终得到了OutOfMemory,我不能杀死这个进程而是杀死-9。我怀疑大多数情况下的内存问题。

2

当进程正常运行时通过jstack -F(-F必须存在,它产生不同于快速jstack的快照)时创建快照。线程号不是Thread.id,而是系统号。 5548似乎是在Finalizer和RefCounter之前创建的(它们不是问题的根源),因此它应该是GC线程或某个编译器。

100%,可能意味着在显示器的一些bug。 Java(热点)监视器使用非常简单的自旋锁定机制来确保所有权。

和当然,附加一个调试器 - GDB检查到底在哪过程中一直坚持。

0

这里有一些工具,你可以用本地化进程的一部分消耗CPU:

  • perf/oprofile,尤其是opannotate - 伟大的看到什么是地狱代码消耗周期
  • stracegstack/gdb(正如其他人所提到的)
  • systemtap功能非常强大,但与基于ptrace的工具的某些相同方式受到限制(如果您的问题不涉及sysc所有这些都不那么有效)。