3

一般建议是,除非在特殊情况下,否则不应捕获 java.lang.Error,请参阅捕获 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

4 回答 4

7

在调用堆栈的最顶部设置异常屏障,捕获并记录所有Throwables 是非常有意义的。在服务器端代码中,这实际上是常态。如果您确保OutOfMemoryError在该级别捕获唯一的,而不是更低的,那么它很有可能不会损害您的系统:随着调用堆栈展开,为服务请求而创建的所有对象都将变得无法访问。由于 OOME 很可能恰好发生在对系统造成最大内存压力的线程中,因此所有内存都将被回收,系统的其余部分将能够再次呼吸。

是的,从技术上讲,总是有机会在块内获得 OOME finally,从而导致资源泄漏或更糟;或者在一些代码中修改了一个长期存在的全局结构,破坏了它的不变量,但在实践中这不太可能。

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

于 2013-01-17T10:30:01.900 回答
2

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

于 2013-01-17T10:29:22.807 回答
0

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

于 2013-01-17T10:35:41.483 回答
0

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

一般来说,OOME 不保证是可恢复的,但也不保证您的程序也会关闭。

于 2013-01-17T10:59:26.043 回答