我们在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负载”可能会导致此问题,我们测试两种情况:
我们开始使用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]
我们启动了几个占用大量内存的其他程序,现在GC日志如下: 11710.051:[GC 11710.058:[ParNew:409472K-> 0K(409536K),5.9080290 secs] 489119K-> 81136K(1638336K),5.9256280 secs]
在这两种情况中的任何一种情况下,Young Generation GC的时间变得更长,但是次要收集的暂停时间与实时时间大致相同,似乎不是其中任何一个导致长时间暂停。
但是其他时间去哪儿了?
答案 0 :(得分:1)
在停止之前,可以执行世界GC,所有线程都必须达到安全点。通常这种情况很快发生,但是一些JNI方法可能会在没有安全点的情况下运行很长时间。这是在GC实际启动之前可以长时间延迟的原因之一。
如果再次看到这一点,那么获得C级堆栈跟踪是值得的(jstack可能在GC执行之后才会响应)