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

Java 当JVM花时间在GC中时,线程转储是什么样子的,java,garbage-collection,thread-dump,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.wai

在分析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)
”1304802943@qtp-对象中的393978767-9985“prio=10 tid=0x00007f3ed02dd000 nid=0x74e7。等待()[0x000000004febb000]
java.lang.Thread.State:定时等待(在对象监视器上)
在java.lang.Object.wait(本机方法)
位于org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:626)
-已锁定(一个org.mortbay.thread.QueuedThreadPool$PoolThread)
"26774405@qtp-对象中的393978767-9984“prio=10 tid=0x00007f3ee4b37000 nid=0x74e6。等待()[0x0000000045d1a000]
java.lang.Thread.State:定时等待(在对象监视器上)
在java.lang.Object.wait(本机方法)
位于org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:626)
-已锁定(一个org.mortbay.thread.QueuedThreadPool$PoolThread)
"764808089@qtp-对象中的393978767-9983“prio=10 tid=0x00007f3ee4c50000 nid=0x74e5。等待()[0x000000004ad6a000]
java.lang.Thread.State:定时等待(在对象监视器上)
在java.lang.Object.wait(本机方法)
位于org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:626)
-已锁定(一个org.mortbay.thread.QueuedThreadPool$PoolThread)
因此,有许多线程处于
TIMED\u等待状态。理论上,在正常运行的应用程序中很容易发现这种情况(应用程序目前根本没有任何传入请求),但我甚至找不到单个请求调度线程做一些有用的事情(标称命中率约为100 hps)


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

我猜您有一个线程池正在等待执行某些操作。如果您的进程是高效的,并且每秒有100个请求,那么即使有一个线程正在执行某项任务,您也可能会遇到问题。我建议您查看进程的CPU负载。如果是50%,您有50%的机会发现一个线程(可能不是请求线程)正在执行某些操作

如果您想查看您的服务器花时间做什么,我会尝试VisualVM之类的探查器,或者YourKit之类的商业探查器

在谷歌搜索你的代码时,我发现了一个不同的版本,但是我怀疑你的线程在run()方法的这个块中是计时的


尝试一个jmap-histo:live随时间推移,您可以比较输出,查看哪些对象类型正在增长

您需要为jmap安装JDK。


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

只回答问题的标题:

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

答案是:你没有办法(以通常的方式)获得这样的垃圾

JVM只在到达后处理线程转储请求,这在GC中是不可能发生的

但是,有一种欺骗方式可以通过未记录的JVMTI函数AsyncGetCallTrace获得活动GC的线程转储,这在本文中提到:


它还提示您可以采用这种混合的本机/java线程转储。

不分析线程转储,而是添加:
-XX:+PrintGCDetails-XX:+PrintGCTimeStamps
以发现长时间运行的GC。
                // We are idle
                // wait for a dispatched job
                synchronized (this)
                {
                    if (_job==null)
                        this.wait(getMaxIdleTimeMs());
                    job=_job;
                    _job=null;
                }