当JVM在GC中花费时间时,线程转储是什么样的

时间:2011-12-07 08:27:21

标签: java garbage-collection thread-dump

在分析Java应用程序时,我注意到有趣的事实。当JVM处于死亡线程转储的GC螺旋时,它看起来像:

"1304802943@qtp-393978767-9985" prio=10 tid=0x00007f3ed02dd000 nid=0x74e7 in Object.wait() [0x000000004febb000]
 java.lang.Thread.State: TIMED_WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:626)
    - locked <0x00000007aed40048> (a org.mortbay.thread.QueuedThreadPool$PoolThread)

"26774405@qtp-393978767-9984" prio=10 tid=0x00007f3ee4b37000 nid=0x74e6 in Object.wait() [0x0000000045d1a000]
   java.lang.Thread.State: TIMED_WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:626)
    - locked <0x00000007aed83aa0> (a org.mortbay.thread.QueuedThreadPool$PoolThread)

"764808089@qtp-393978767-9983" prio=10 tid=0x00007f3ee4c50000 nid=0x74e5 in Object.wait() [0x000000004ad6a000]
   java.lang.Thread.State: TIMED_WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:626)
    - locked <0x00000007aed5c448> (a org.mortbay.thread.QueuedThreadPool$PoolThread)

因此,TIMED_WAITING状态中有很多线程。从理论上讲,这种情况很容易在正常运行的应用程序中找到(应用程序此刻根本没有任何传入请求),但我甚至找不到单个请求调度线程做一些有用的事情(名义命中率约为100 hps)。

这种行为是否与GC有关,或者只是巧合?

3 个答案:

答案 0 :(得分:3)

回答问题的标题:

  

当JVM在GC中花费时间时,线程转储是什么样的?

答案是:你无法以通常的方式获得这种转储。

JVM仅在到达safepoint后处理线程转储请求,这在GC中不会发生。

但是在这篇文章中提到的未记录的JVMTI函数AsyncGetCallTrace的帮助下,有一种获取活动GC的线程转储的作弊方法:

http://jeremymanson.blogspot.com/2010/07/why-many-profilers-have-serious.html

它还暗示Oracle Solaris Studio可以be used采用这种混合的本机/ java线程转储。

答案 1 :(得分:1)

尝试jmap -histo:随着时间的推移,你可以比较输出,看看哪些对象类型正在增长。

您需要为jmap安装JDK。 http://docs.oracle.com/javase/6/docs/technotes/tools/share/jmap.html

一个警告,jmap是密集的,它将在它运行时暂停所有线程,这应该只有几秒钟。进程可以核心转储,因为它是密集的,通常它是快速和安全的,但我已经看到它锁定或杀死大型应用程序,多gig堆。

答案 2 :(得分:0)

我的猜测是你有一个等待做某事的线程池。如果您的流程效率很高,而且每秒甚至有100个请求,那么即使是一个线程执行某些操作也可能无法捕获。我建议你看一下你的进程的CPU负载。如果是50%,你有50%的机会找到一个线程(可能不是请求线程)做某事。

如果你想看看服务器花费的时间,我会尝试使用像VisualVM这样的分析器,或像YourKit这样的商业分析器。

谷歌搜索你的代码,我发现了一个不同的版本http://grepcode.com/file/repo1.maven.org/maven2/org.mortbay.jetty/jetty-util/7.0.0.pre5/org/mortbay/thread/QueuedThreadPool.java但我怀疑你的线程在这个块中是TIMED_WAIT int run#()方法

                // We are idle
                // wait for a dispatched job
                synchronized (this)
                {
                    if (_job==null)
                        this.wait(getMaxIdleTimeMs());
                    job=_job;
                    _job=null;
                }