我有一个与-Xmx2g
非常愉快地运行的程序。随着-Xmx1g
,它会停止。它永远不会出现内存异常 - 或者至少,我从来没有耐心等待足够长的时间。
这表明总足迹确实适合1克,但GC对可能耗尽空间感到担忧。
内存占用量是一些大而稳定的项目的组合,具有大量短暂的流量。
任何一个或多或少模糊的GC选项是否与这种情况相关?
答案 0 :(得分: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?)。
答案 1 :(得分:3)
听起来你没有给JVM足够的堆。当然,工作集可能适合1Gbytes,但你仍然需要更多。要了解原因,请继续阅读。
让我们假设当垃圾收集器运行时,它会执行一定量的工作W1
,该工作量与其扫描的非垃圾量成比例,以便识别垃圾和另一项工作量{{ 1}}与它找到的垃圾量成正比。 (事实上,它比这更复杂......但是让分析变得简单。)
假设您有一个堆1Gb堆,其中0.9Gb被可访问对象占用。每次GC运行时,它都可以回收最多0.1Gb的堆空间,这样做需要W2
工作。回收的每字节工作量为W1 * 0.9Gb + W2 * 0.1Gb
;即(W1 * 0.9Gb + W2 * 0.1Gb) / 0.1Gb
。
现在假设您有一个2Gb堆,其中0.9Gb被可访问对象占用。现在回收的每字节工作量为9 * W1 + W2
或(W1 * 0.9Gb + W2 * 1.1Gb) / 1.1Gb
。
如果比较这两个,您会发现与2Gb堆相比,GC在1Gb堆中回收的每字节大约W1 * 9/11 + W2
个工作量大约W1 * 8
。
作为一般规则,运行堆越接近完整,垃圾收集器的效率就越低。课程是:
将JVM配置为使用大量堆,
配置JVM以在运行完整GC后,如果有少于(例如)25%的堆空闲时抛出OOM。
答案 2 :(得分:2)
在很多情况下,对于OOME来说,真的很长时间。这是因为,当GC开始努力工作时,它会停止程序中的所有活动。如果您通常每0.01秒的GC时间获得1秒的有用程序时间,在这些情况下,您可能会看到它完全相反 - 每1秒GC时间有效程序时间为0.01秒。按照这个速度,吃掉1 GB堆中最后512k可能需要花费很长的时间。
VisualVM及其VisualGC插件是你的朋友;当你处于这种状态时,他们的图表将显示出不同的模式。
答案 3 :(得分:0)
如果你不想做一些微调,你应该检查MinHeapFreeRatio
和MaxHeapFreeRatio
参数以及其他所谓的Java SE 6 HotSpot[tm] Virtual Machine Garbage Collection Tuning参数,这会导致“镇静剂效应”。