调整Java GC,以便它立即抛出OOME,而不是不确定地减速

时间:2011-07-15 10:36:23

标签: java performance memory-management garbage-collection jvm

我注意到,有时候,当内存几乎耗尽时,GC会尝试以任何性能价格完成(导致程序几乎冻结,有时多分钟),而不是只需立即抛出OOME(OutOfMemoryError)。

有没有办法在这方面调整GC?

将程序降低到接近零速度会使其无响应。在某些情况下,最好是回复“我死了”,而不是根本没有回应。

4 个答案:

答案 0 :(得分:8)

像你所追求的东西被内置到最近的JVM中。

如果你:

  • 正在使用来自(至少)Java 6的Hotspot VM
  • 正在使用并行或并发垃圾收集器
  • 启用了选项UseGCOverheadLimit(默认情况下,这些收集器已启用,因此更具体地说,如果您没有禁用它)

然后你会在实际耗尽内存之前获得一个OOM:如果最近98%的时间花在了GC上以恢复<2%的堆大小,那么你将获得一个抢先的OOM。 / p>

调整这些参数(特别是98%)听起来对你有用,但是据我所知,没有办法调整这些阈值。

但是,请检查您是否符合上述三点要求;如果您没有使用带有该旗帜的收藏家,这可能有助于您的情况。

值得一读the HotSpot JVM tuning guide,这对这些东西有很大的帮助。

答案 1 :(得分:2)

我不知道以您描述的方式配置Java垃圾收集器的任何方法。

一种方法可能是您的应用程序主动监控可用内存量,例如:使用Runtime.freeMemory(),并声明“我死了”条件,如果它低于某个阈值并且无法通过强制垃圾回收周期进行纠正。

我们的想法是选择足够大的阈值,使流程永远不会陷入您描述的情况。

答案 2 :(得分:1)

我强烈建议不要这样做,Java尝试GC而不是立即抛出OutOfMemoryException更有意义 - 除非每个替代方案已经用尽,否则不要让你的应用程序崩溃。

如果你的应用程序内存不足,你应该增加最大堆大小,或者根据内存分配查看它的性能,看看它是否可以优化。

要注意的一些事情是:

  • 如果未在其他地方引用,则在不需要对象的位置使用弱引用。
  • 不要分配比你需要的更大的对象(例如,当你只需要通过数组生命周期访问其中的三个时,存储大量的100个对象),或者当你只需要存储时使用long数据类型八个值。
  • 不要持久于对象的引用!

编辑:我认为你误解了我的观点。如果您不小心将实时引用留给了不再需要使用的对象,那么显然仍然不会进行垃圾回收。这与使用null-only无关 - 这是一个典型的例子,它将使用一个大对象用于特定目的,但是当它超出范围时它不是GC,因为实时引用意外地遗留在别处,某处你不知道造成泄漏。一个典型的例子是哈希表查找,可以用弱引用来解决,因为只有弱可达时才有资格获得GC。

无论这些只是关于如何通过内存分配提高性能的一般想法。我试图提出的问题是,询问如何更快地抛出OutOfMemory错误,而不是让Java GC尝试最好释放堆上的空间,这不是一个好主意IMO。改为优化您的应用程序。

答案 3 :(得分:0)

事实证明,自 Java8 b92 以来,有一种解决方案:

-XX:+ExitOnOutOfMemoryError
启用此选项后,JVM会在第一次出现内存不足错误时退出。如果您希望重新启动JVM实例而不是处理内存不足错误,可以使用它。

-XX:+CrashOnOutOfMemoryError
如果启用此选项,则当发生内存不足错误时,JVM崩溃并生成文本和二进制崩溃文件(如果启用了核心文件)。

一个好主意是将上述选项之一与旧的-XX:+HeapDumpOnOutOfMemoryError

结合起来

我测试了这些选项,它们实际上按预期运行!

链接

See the feature description

See List of changes in that Java release