需要解释明显的堆大小减少

时间:2013-12-19 14:28:59

标签: java memory garbage-collection stack heap

从GC日志来看,似乎在一段时间后,年龄和老年人的堆大小正在减少。

以下是日志中的三个条目。

{gc invocations之前的堆= 5:

PSYoungGen总计44800K,使用44180K [0x18220000,0x1b420000,0x24a20000]

伊甸园空间38400K,100%使用[0x18220000,0x1a7a0000,0x1a7a0000]

来自6400K空间,90%使用[0x1ade0000,0x1b3853c8,0x1b420000]

到空间6400K,0%使用[0x1a7a0000,0x1a7a0000,0x1ade0000]

PSOldGen总计51200K,使用16K [0x0ba20000,0x0ec20000,0x18220000]

对象空间51200K,使用0%[0x0ba20000,0x0ba24128,0x0ec20000]

PSPermGen总计32768K,使用12417K [0x03a20000,0x05a20000,0x0ba20000]

对象空间32768K,37%使用[0x03a20000,0x046406c0,0x05a20000)

1047.599:[GC [PSYoungGen:44180K-> 5990K(44032K)] 44197K-> 6006K(95232K),0.0046671 secs]

gc invocations = 5后的堆:

PSYoungGen总计44032K,使用5990K [0x18220000,0x1b5a0000,0x24a20000]

伊甸园空间37632K,0%使用[0x18220000,0x18220000,0x1a6e0000)

来自6400K空间,93%使用[0x1a7a0000,0x1ad79990,0x1ade0000]

到空间7552K,0%使用[0x1ae40000,0x1ae40000,0x1b5a0000]

PSOldGen总计51200K,使用16K [0x0ba20000,0x0ec20000,0x18220000]

对象空间51200K,使用0%[0x0ba20000,0x0ba24128,0x0ec20000]

PSPermGen总计32768K,使用12417K [0x03a20000,0x05a20000,0x0ba20000]

对象空间32768K,37%使用[0x03a20000,0x046406c0,0x05a20000)

}


{gc invocations之前的堆= 174:

PSYoungGen总计9728K,使用9666K [0x18220000,0x18d30000,0x24a20000]

伊甸园空间8640K,99%使用[0x18220000,0x18a8fa58,0x18a90000)

来自太空1088K,94%使用[0x18a90000,0x18b910f0,0x18ba0000]

到空格1344K,0%使用[0x18be0000,0x18be0000,0x18d30000)

PSOldGen总计51200K,使用21113K [0x0ba20000,0x0ec20000,0x18220000]

对象空间51200K,41%使用[0x0ba20000,0x0cebe540,0x0ec20000]

PSPermGen总计32768K,使用12611K [0x03a20000,0x05a20000,0x0ba20000]

对象空间32768K,38%使用[0x03a20000,0x04670fa0,0x05a20000)

26968.748:[GC [PSYoungGen:9666K-> 1271K(9920K)] 30780K-> 22465K(61120K),0.0025274秒]

gc invocations = 174后的堆:

PSYoungGen总计9920K,使用1271K [0x18220000,0x18d50000,0x24a20000]

伊甸园空间8576K,使用0%[0x18220000,0x18220000,0x18a80000]

来自太空1344K,94%使用[0x18be0000,0x18d1dd00,0x18d30000]

到空间1408K,使用0%[0x18a80000,0x18a80000,0x18be0000]

PSOldGen总计51200K,使用21194K [0x0ba20000,0x0ec20000,0x18220000]

对象空间51200K,41%使用[0x0ba20000,0x0ced29e0,0x0ec20000)

PSPermGen总计32768K,使用12611K [0x03a20000,0x05a20000,0x0ba20000]

对象空间32768K,38%使用[0x03a20000,0x04670fa0,0x05a20000)

}


{gc invocations之前的堆= 23195:

PSYoungGen总计1536K,使用1372K [0x18220000,0x18440000,0x24a20000]

伊甸园空间896K,100%使用[0x18220000,0x18300000,0x18300000]

来自640K空间,74%使用[0x183a0000,0x184173e8,0x18440000]

到空间640K,使用0%[0x18300000,0x18300000,0x183a0000]

PSOldGen总计6272K,使用4627K [0x0ba20000,0x0c040000,0x18220000]

对象空间6272K,使用率为73%[0x0ba20000,0x0bea4d70,0x0c040000]

PSPermGen总计32768K,使用12930K [0x03a20000,0x05a20000,0x0ba20000]

对象空间32768K,39%使用[0x03a20000,0x046c0aa0,0x05a20000)

71908.146:[GC [PSYoungGen:1372K-> 533K(1536K)] 6000K-> 5423K(7808K),0.0107964 secs]

gc调用后的堆= 23195:

PSYoungGen总计1536K,使用533K [0x18220000,0x18460000,0x24a20000]

伊甸园空间896K,使用0%[0x18220000,0x18220000,0x18300000]

来自太空640K,83%使用[0x18300000,0x18385438,0x183a0000]

到空间704K,0%使用[0x183b0000,0x183b0000,0x18460000]

PSOldGen总计6272K,使用4890K [0x0ba20000,0x0c040000,0x18220000]

对象空间6272K,使用率为77%[0x0ba20000,0x0bee6868,0x0c040000]

PSPermGen总计32768K,使用12930K [0x03a20000,0x05a20000,0x0ba20000]

对象空间32768K,39%使用[0x03a20000,0x046c0aa0,0x05a20000)

}


使用的(相关)JVM参数如下:

-server

-Xms600m

-Xss256k

-XX:+ UseParallelGC

-XX:+ PrintHeapAtGC

-XX:+ HeapDumpOnOutOfMemoryError

-Xloggc:verbose_gc.log

-Djavax.net.debug =无

-XX:+ PrintGCDetails

-XX:+ PrintTenuringDistribution

-XX:+ PrintClassHistogram

-Xmx800m

-XX:NewRatio = 1

-XX:CompileThreshold = 1500

-XX:PermSize =32米

-XX:MaxPermSize参数=128米

假设存储器被太多线程消耗(基于对堆栈内存与堆内存不同的理解),使用visual vm观察时,使用简单创建新线程的示例应用程序显示为假(年轻和终身的世代充满了)。

这种行为有什么解释吗?

更新#1: 更正和更新: 上面的示例应用程序还包括使用每个线程创建的数组对象。数组大小是总堆的非常重要的一部分。 这个问题在JDK 1.5中可以观察到。

-R

2 个答案:

答案 0 :(得分:1)

实际上,这是JVM的正常行为。当JVM注意到您没有使用当前分配的某些HEAP内存时,它会假定您的应用程序可以以低于您提供的速度运行,并且会在垃圾回收期间减少堆的总大小(但绝不低于您使用-Xms指定的最小堆大小)将内存释放回操作系统。

如果将来事实证明您的应用程序实际上需要使用更多堆内存,JVM将从操作系统保留更多内存(直到您使用-Xmx指定的最大堆大小)。

我已经看到过这种情况发生在我的一些webapps上,这似乎是正常的行为。这样做的问题在于,当应用程序突然需要比平时更多的内存时,这种堆的减少会导致一些不必要的完全垃圾收集。

就我而言,堆大小的减少导致了太多的世界末日垃圾收集。我们通过使最小堆大小更接近最大堆大小来解决问题。如果您确实希望避免此行为,可以将最小堆大小设置为等于最大堆大小。

另请注意,线程堆栈空间占用的内存不计入堆IIRC的一部分。

答案 1 :(得分:0)

从进一步研究的内容来看,线程似乎确实存在问题。

创建了早期的数组(理解它们将成为堆栈内存的一部分,但它们是堆的一部分)。 The Heap

没有数组,问题可以在JDK 1.5.14上重现。然而,它不是JDK 1.6.37。 线程池的使用可能掩盖了导致上述gc样本的问题。

更新#1:

确定1.5的合理解决方案是在参数中包含'-XX:NewSize'(伊甸园不会降低到该值以下)但是不知道这是否会解决问题(回收的内存但没有考虑)或者是否会出现内存不足问题(内存未回收)

其他链接:

https://bugs.openjdk.java.net/browse/JDK-7118202(与JDK-7相关:可能的解释以及导致它的原因)

https://www.java.net//node/662483