Java中捕获OutOfMemoryError

在本教程中,我们将学习如何在发生OutOfMemoryError时显式停止应用程序。在某些情况下,如果没有正确的处理,我们可能会在不正确的状态下继续处理应用程序。

什么是OutOfMemoryError
OutOfMemoryError是应用程序外部的错误,并且是不可恢复的,至少在大多数情况下是这样。错误名称表明应用程序没有足够的 RAM,但这并不完全正确。更准确地说,应用程序无法分配所请求的内存量。

在单线程应用程序中,情况非常简单。如果我们遵循准则并且没有捕获OutOfMemoryError,应用程序将终止。这是处理此错误的预期方法。

在某些特定情况下,捕获OutOfMemoryError是合理的。此外,我们还可以制定一些更具体的计划,以便在其之后继续进行可能是合理的。然而,在大多数情况下,OutOfMemoryError意味着应用程序应该停止。

如何捕获?
想象一下,我们正在处理一个包含历史银行数据的巨大 XML 文件。我们将块加载到内存中,进行计算,并将结果写入光盘。该示例可以更复杂,但主要思想是,有时,我们严重依赖线程中进程的事务性和正确性。

幸运的是,JVM将OutOfMemoryError视为一种特殊情况,我们可以使用以下参数在应用程序中出现OutOfMemoryError时退出或崩溃 JVM:

-XX:+ExitOnOutOfMemoryError
-XX:+CrashOnOutOfMemoryError

如果我们使用这些参数中的任何一个运行示例,应用程序将停止。这将使我们能够调查问题并检查发生了什么。

这些选项之间的区别在于-XX:+CrashOnOutOfMemoryError会生成故障转储:

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  Internal Error (debug.cpp:368), pid=69477, tid=39939
#  fatal error: OutOfMemory encountered: Java heap space
#
...

它包含我们可用于分析的信息。为了使这个过程更容易,我们还可以进行堆转储来进一步调查它。有一个特殊选项可以在OutOfMemoryError上自动执行此操作。

我们还可以为多线程应用程序创建线程转储。

但是,我们可以使用脚本并通过OutOfMemoryError触发它。

如果我们想以类似方式处理其他异常,就必须使用 Futures 来确保线程按计划完成工作。

总结

  • 在某些情况下,忽略OutOfMemoryError是合理的。我们不想因为错误或用户漏洞而杀死整个Web服务器。
  • 此外,实际应用程序中的行为可能有所不同:线程和其他共享资源之间可能存在互连性。因此,任何线程都可以抛出OutOfMemoryError。
  • 线程关于异常的规则:线程中发生的事情保留在线程中。
  • 即使线程中最严重的错误也不会传播到主应用程序
  • 如果主应用程序线程中没有发生OutOfMemoryError,应用程序仍应运行。