Java内存溢出然后退出

3
我有一个需要分析大文件的软件。限制输入或提供无限内存都不是选项,所以我必须接受飞行中的 OOME。由于 OOME 只会杀死线程,因此我的软件在某种糟糕的状态下运行。
从外部看,一切都很好,因为进程正在运行,但从内部来看它已经失去了功能。
我想断开它的电源。但是我该如何做呢?
捕获 OOME 并不能保证下一行代码将被执行。例如 System.exit(9)。因此 JVM 必须注意到 OOME 并销毁自身。
是否有一些 VM 选项可以实现这一点?

1
“捕获 OOME 并不能保证下一行代码会被执行。”你有相关的参考资料吗? - aioobe
3个回答

8

当您遇到 OOME 时,可能会非常缺乏内存,而日志记录并不总是有效。解决这个问题的一种方法是拥有一个关机方法,在关闭之前保留一些不释放的内存。

例如:

 private static byte[] lastResort = new byte[256*1024];
 public static void handleOOME(OutOfMemoryError oome) {
     lastResort = null;
     try {
        LOG.fatal("Dying after ", oome);
     } finally {
        System.exit(-1);
     }
  }

2
有趣的方法!你在生产环境中使用过吗? - Joachim Sauer
1
勇敢、奇特、叛逆 :p - Yngve Sneen Lindal
@JoachimSauer 我在生产中使用了64KB保留。 - Peter Lawrey

3
您可以使用-XX:+ExitOnOutOfMemoryError - 支持Java 8更新92。
您还可以使用-XX:+CrashOnOutOfMemoryError来获取核心转储以进行进一步的调查。
您还可以使用-XX:+HeapDumpOnOutOfMemoryError在OOME上生成堆转储以进行进一步的调查。
来源:这里这里

2
因此,JVM必须注意到OOME并销毁自身。是否有某个vm选项可用于此?
没有这样的选项。
然而,我必须质疑您不能捕获OutOfMemoryError并在异常处理程序中立即调用System.exit()的假设。
在实践中,它应该可以工作。唯一可能的问题是,如果您调用了Runtime.setRunFinalizersOnExit(true) ……即使您使用非零退出状态退出,也会被忽略。
(关于捕获OOME和其他随机错误异常的警告是,JVM可能不适合继续执行。但调用System.exit(nonzero)不会这样做!)

它是有效的,我已经编写了一个Swing程序来捕获OutOfMemoryError,然后在屏幕上显示相关信息。 - Adam
在调用堆栈的几个级别下捕获OOME可能会释放足够的内存进行一些基本的日志记录/错误处理(因为来自调用堆栈的GC根会消失)。 - Joachim Sauer
没错,@Peter Lawrey的回答是另一种方法。(我在其他情况下也见过这种做法。例如,一些JVM会这样做来为创建OOME及其堆栈帧保留空间。) - Stephen C

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接