【问题标题】:Need an explanation for apparent heap size reduction需要解释明显的堆大小减少
【发布时间】:2014-01-08 04:09:24
【问题描述】:

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

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

{gc 调用之前的堆=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 秒]

gc 调用后堆=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 调用之前的堆=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 调用后的堆=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 调用之前的堆=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 秒]

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参数如下:

-服务器

-Xms600m

-Xss256k

-XX:+UseParallelGC

-XX:+PrintHeapAtGC

-XX:+HeapDumpOnOutOfMemoryError

-Xloggc:verbose_gc.log

-Djavax.net.debug=none

-XX:+PrintGCDetails

-XX:+PrintTenuringDistribution

-XX:+PrintClassHistogram

-Xmx800m

-XX:NewRatio=1

-XX:CompileThreshold=1500

-XX:PermSize=32m

-XX:MaxPermSize=128m

当使用可视 vm (the年轻一代和老一代人满了)。

对这种行为有什么解释吗?

更新#1: 更正和更新: 上面的示例应用程序还包括一个与每个线程一起创建的数组对象。数组大小是总堆的重要部分。 该问题在 JDK 1.5 中很明显。

-R

【问题讨论】:

    标签: java memory garbage-collection heap-memory stack-memory


    【解决方案1】:

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

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

    我在过去的一些 web 应用中看到过这种情况,这似乎是正常行为。这样做的问题在于,当您的应用程序突然需要比平时更多的内存时,这种堆的减少可能会导致一些不需要的完整垃圾回收。

    在我的例子中,堆大小的减少导致了太多的 stop-the-world 完整垃圾回收。我们通过使最小堆大小更接近最大堆大小来解决此问题。如果您真的想避免这种行为,可以将最小堆大小设置为等于最大堆大小。

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

    【讨论】:

    • 谢谢!此外,您能否进一步了解线程内存的分配方式? (或者指向相同的资源?)
    • 也许这个答案可以帮助您了解线程内存:stackoverflow.com/questions/16264118/…
    • 更“轻”,你可以下载OpenJDK源代码,看看线程“启动”时调用的native code方法。
    【解决方案2】:

    从进一步调查的结果来看,这似乎是线程的问题。

    创建了较早的数组(理解它们将是堆栈内存的一部分,但它们在很大程度上是堆的一部分)。 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

    【讨论】:

      猜你喜欢
      • 2017-08-21
      • 2016-04-25
      • 2022-12-19
      • 2020-04-24
      • 2016-11-12
      • 2012-01-23
      • 2014-11-13
      • 2012-11-16
      相关资源
      最近更新 更多