安抚兴奋的垃圾收集器
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.1Gb
或W1 * 9/11 + W2
。
如果您比较这两者,您会发现与 2Gb 堆相比,GC 在 1Gb 堆中回收的每个字节的工作量大约为W1 * 8
。
一般来说,运行堆越接近满,垃圾收集器的效率就越低。教训是:
将 JVM 配置为使用大堆,并且
将 JVM 配置为在运行完整 GC 后如果有少于(例如)25% 的堆空闲则抛出 OOM。
【讨论】:
【参考方案2】:如果您不想进行微调,您应该检查 MinHeapFreeRatio
和 MaxHeapFreeRatio
参数以及此处描述的其他参数 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?)。
【讨论】:
以上是关于安抚兴奋的垃圾收集器的主要内容,如果未能解决你的问题,请参考以下文章