安抚兴奋的垃圾收集器

Posted

技术标签:

【中文标题】安抚兴奋的垃圾收集器【英文标题】:Calming an excited Garbage Collector 【发布时间】:2011-01-17 16:05:36 【问题描述】:

我有一个使用-Xmx2g 运行得非常愉快的程序。使用-Xmx1g,它会停止。它永远不会出现内存不足的异常——或者,至少,我从来没有耐心等待足够长的时间。

这表明总占用空间确实适合 1g,但 GC 担心可能会用完空间。

内存占用是一些具有大量短暂流量的大型稳定项目的组合。

是否有任何或多或少晦涩难懂的 GC 选项与这种情况相关?

【问题讨论】:

我就在那里,打算给他们打招呼的小贴士,并给他们圣诞节的小贴士。 @Pekka:请解释一下... @JRL 他在想开卡车的人。 【参考方案1】:

听起来你没有给 JVM 足够的堆。当然,工作集可能适合 1GB,但您仍然需要提供更多。要了解原因,请继续阅读。

让我们假设,当垃圾收集器运行时,它执行的工作量W1 与它为识别垃圾而扫描的非垃圾量成正比,而另一量的工作量W2与它发现的垃圾量成正比。 (其实比这复杂一点……不过还是让分析简单点吧。)

假设您有一个 1Gb 堆,其中 0.9Gb 被可访问对象占用。每次 GC 运行时,它最多可以回收 0.1Gb 的堆空间,这样做需要做W1 * 0.9Gb + W2 * 0.1Gb 的工作。每字节回收的工作量为(W1 * 0.9Gb + W2 * 0.1Gb) / 0.1Gb;即9 * W1 + W2

现在假设您有一个 2Gb 堆,其中 0.9Gb 被可访问对象占用。现在每字节回收的工作量是(W1 * 0.9Gb + W2 * 1.1Gb) / 1.1GbW1 * 9/11 + W2

如果您比较这两者,您会发现与 2Gb 堆相比,GC 在 1Gb 堆中回收的每个字节的工作量大约为W1 * 8

一般来说,运行堆越接近满,垃圾收集器的效率就越低。教训是:

将 JVM 配置为使用大堆,并且

将 JVM 配置为在运行完整 GC 后如果有少于(例如)25% 的堆空闲则抛出 OOM。

【讨论】:

【参考方案2】:

如果您不想进行微调,您应该检查 MinHeapFreeRatioMaxHeapFreeRatio 参数以及此处描述的其他参数 Java SE 6 HotSpot[tm] Virtual Machine Garbage Collection Tuning 这会导致“镇静剂效应”。

【讨论】:

【参考方案3】:

在许多情况下,OOME 可能需要 真的 很长时间。这是因为,当 GC 开始努力工作时,它会停止程序中的所有活动。例如,如果您通常每 0.01 秒的 GC 时间获得 1 秒的有用程序时间,那么在这些情况下,您可能会看到它完全颠倒了 - 每 1 秒的 GC 时间有 0.01 秒的有用程序时间。按照这个速度,吃完 1 GB 堆的最后 512k 可能需要相当长的时间。

VisualVM 和它的 VisualGC 插件是你的朋友;当你处于这种状态时,他们的图表会显示出不同的模式。

【讨论】:

【参考方案4】:

您可以在 JVM 上使用http://java.sun.com/docs/hotspot/gc5.0/gc_tuning_5.html 设置大量用于垃圾收集的选项。当应用程序由于 GC 导致停止时,您通常会看到很多主要收集,这可能会在收集时停止一切。您可以调整次要收集参数和主要收集参数,以查看是否可以进行更频繁的次要收集。

我建议使用 VisualVM(JDK6 附带,我相信更新 7+)之类的工具来查看占用堆的内容并分析对象图。另请查看用于分析 hprof 文件的工具 (How do I analyze a .hprof file?)。

【讨论】:

以上是关于安抚兴奋的垃圾收集器的主要内容,如果未能解决你的问题,请参考以下文章

垃圾收集器与内存分配策略之垃圾收集器

JVM垃圾回收-7种垃圾收集器

垃圾收集器(垃圾收集算法的实现)

垃圾收集器(垃圾收集算法的实现)

JVM之垃圾收集算法与垃圾收集器

G1垃圾收集器介绍