我应该捕获OutOfMemoryError吗?

时间:2013-01-17 10:25:58

标签: java out-of-memory

一般建议是你不应该捕获java.lang.Error,除非在特殊情况下,例如参见Is it a bad practice to catch Throwable?

我的情况是我有一个程序有时耗尽内存并抛出java.lang.OutOfMemoryError。虽然没有从中恢复但我确实想知道它发生了,所以我希望在日志中看到一些东西和非零退出代码。那么这样的建议是什么意思吗?

public static void main(String[] args)
{
    try
    {
        ...
    }
    catch (Exception e)
    {
        e.printStackTrace();
        System.exit(1);
    }
    catch (OutOfMemoryError e)
    {
        e.printStackTrace();
        System.exit(1);
    }
}

另一个程序是类似的,除了它可能是一个占用所有内存的特定线程。在这种情况下,如果该线程退出,则可以继续处理,我真正想要的只是查看日志并最终具有非零退出代码。那么我应该在那个线程运行方法中捕获OutOfMemoryError吗?

4 个答案:

答案 0 :(得分:7)

在调用堆栈的最顶端有一个异常屏障,捕获并记录所有Throwable,这是很有意义的。在服务器端代码中,这实际上是常态。如果确保仅在该级别捕获OutOfMemoryError,而不是低于任何地方,则很有可能它不会损害您的系统:当调用堆栈展开时,为创建请求而创建的所有对象将变得无法到达。由于OOME很可能恰好出现在系统中造成最强记忆压力的线程中,所有记忆都将被回收,系统的其余部分将能够再次呼吸。

是的,从技术上讲,总有一个机会让OOME进入finally区域,导致资源泄漏或更糟;或者在一些修改了长寿命的全局结构的代码中,打破了它的不变量,但在实践中它是不太可能的。

在决定您对OOME的政策时,请记住,您的应用程序受到许多不可预测因素的影响,这些因素或多或少会降低其稳定性。 OOME只是该频谱中的另一个点,通常其风险影响不是特别高。

答案 1 :(得分:2)

通常会捕获它,但只能在线程的最高级别。最简单的方法是使用uncaughtexception处理程序。这是抛出异常时调用的函数。此时,您可以记录它并告诉用户您退出应用程序的原因。

答案 2 :(得分:0)

一般规则是:任何例外都应该由最有能力做出充分反应的模块捕获。如果当前方法不知道该怎么做,它应该让异常通过,直到到达main()或run()方法。那些方法不能指望有更有能力的方法,所以他们可以捕捉,记录或浇水。

答案 3 :(得分:0)

在上面的示例中,我认为这是一个好主意,因此您可以控制程序关闭的方式。如果你没有捕获到这个错误,其他线程可能继续运行不正确(错误只在一个线程中抛出)它还在调用shell可以检查时给出退出代码。我会为此错误使用不同的退出代码。

一般情况下,OOME不保证可以恢复,但不保证您的程序也会关闭。