现已知代码A可能诱发OOM。代码B可替代代码A但可维护性差。我希望能先尝试执行代码A,如果发生OOM,则退回来执行代码B。
那么如下代码可行吗?

try {
	代码A
} catch (OutOfMemoryError ignored) {
	代码B
}

试验了一下似乎可行。但一般认为OOM发生在系统层级,上述代码无法获得期望效果。

只有在一种情况下,这样做是可行:在try语句中声明了很大的对象,导致OOM,并且可以确认OOM是由try语句中的对象声明导致的,则在catch语句中,可以释放掉这些对象,解决OOM,继续执行剩余语句。但这通常不是合适做法。

因为OOMError是可以catch的。catch之后吞掉的话程序还能试着继续运行。比如一个Java服务器端应用,有段代码没写对导致有一个线程在疯狂创建大数组对象——直到OOM。这个线程注册的uncaught exception handler捕获到了这个异常,记录了日志,然后就把这个异常吞掉了。这样还能继续正常跑下去是因为:只是一个创建很大的数组对象的请求失败了而已,而出错的那个方法由于异常处理已经被退出了,程序的其它部分并没有受影响。

Java中管理内存除了显式catch OOM外还有更多有效的方法:比如SoftReference, WeakReference, 硬盘缓存等。在JVM用光内存之前,会多次触发GC,这些GC会降低程序运行效率。如果OOM的原因不是try语句中的对象(比如内存泄漏),那么在catch语句中会继续抛出OOM!

参考

  • https://www.zhihu.com/question/54630917/answer/140320945
  • https://www.zhihu.com/question/33194730