YGC(ParNew)的实时时间远远超过用户+ sys时间

时间:2011-12-03 07:22:27

标签: java garbage-collection jvm

我们在JBoss上运行基于Web Java的应用程序,允许的最大堆大小约为2.2 GB(Young Generation为400MB,总机器物理内存为4 GB)。在某些时候,应用程序停止响应(对客户端)几分钟。经过一些分析,我们发现罪魁祸首是Young Generation GC。以下是详细GC日志的摘录:

Heap before GC invocations=3844 (full 7):
 par new generation   total 614336K, used 614272K,  eden space 614272K, 100% used,  from space 64K,   0% used,  to   space 64K,   0% used , concurrent mark-sweep generation total 921600K, used 690936K, concurrent-mark-sweep perm gen total 262144K, used 65905K 2679114.965: [GC 2681684.725: [ParNew: 614272K->0K(614336K), 0.0132460 secs] 1305208K->692360K(1535936K), 0.0135020 secs] [Times: user=0.03 sys=0.03, real=2569.62 secs] 
Heap after GC invocations=3845 (full 7):
 par new generation   total 614336K, used 0K,  eden space 614272K,   0% used,  from space 64K,  to   space 64K,   0% used, concurrent mark-sweep generation total 921600K, used 692360K, concurrent-mark-sweep perm gen total 262144K, used 65905K
Total time for which application threads were stopped: 2569.7748610 seconds

我不明白的是,在ParNew GC上花费的实际时间大约是42分钟(2569秒),而用户+系统时间仅为0.06秒,而次要收集的暂停时间是0.0132460秒。

我们猜测“虚拟内存抖动”或“高CPU负载”可能会导致此问题,我们测试两种情况:

  1. 我们开始使用while循环来使用100%cpu的其他几个程序,GC日志如下: 6052.217:[GC 6052.217:[ParNew:409288K-> 0K(409536K),1.9456320 secs] 480161K-> 72140K(1638336K),1.9460370 secs] [次:用户= 0.03 sys = 0.00,real = 1.95 secs]

  2. 我们启动了几个占用大量内存的其他程序,现在GC日志如下: 11710.051:[GC 11710.058:[ParNew:409472K-> 0K(409536K),5.9080290 secs] 489119K-> 81136K(1638336K),5.9256280 secs]

  3. 在这两种情况中的任何一种情况下,Young Generation GC的时间变得更长,但是次要收集的暂停时间与实时时间大致相同,似乎不是其中任何一个导致长时间暂停。

    但是其他时间去哪儿了?

1 个答案:

答案 0 :(得分:1)

在停止之前,可以执行世界GC,所有线程都必须达到安全点。通常这种情况很快发生,但是一些JNI方法可能会在没有安全点的情况下运行很长时间。这是在GC实际启动之前可以长时间延迟的原因之一。

如果再次看到这一点,那么获得C级堆栈跟踪是值得的(jstack可能在GC执行之后才会响应)