OOME属于一类通常不应该从中恢复的错误。但如果它被嵌在一个线程中,或者有人捕获了它,那么应用程序可能会进入一种既不退出也不有用的状态。即使面对可能愚蠢地尝试捕获Throwable或Error/OOME的库,如何防止这种情况发生?(也就是说,您无法直接访问修改源代码)有什么建议吗?
OOME属于一类通常不应该从中恢复的错误。但如果它被嵌在一个线程中,或者有人捕获了它,那么应用程序可能会进入一种既不退出也不有用的状态。即使面对可能愚蠢地尝试捕获Throwable或Error/OOME的库,如何防止这种情况发生?(也就是说,您无法直接访问修改源代码)有什么建议吗?
解决方案:
在较新的JVM上:
-XX:+ExitOnOutOfMemoryError
to exit on OOME, or to crash:
-XX:+CrashOnOutOfMemoryError
在旧版本中:
-XX:OnOutOfMemoryError="<cmd args>; <cmd args>"
定义:在首次抛出OutOfMemoryError时运行用户自定义命令。 (引入于1.4.2更新12、6版本)
请参见http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html
一个杀死正在运行进程的示例:
-XX:OnOutOfMemoryError="kill -9 %p"
kill -9
终止JVM可能会产生不良副作用。 - Stephen C-XX:OnOutOfMemoryError="kill -9 $PPID"
。 - Po' Lazarus编辑 OutOfMemoryError.java
文件,在其构造函数中添加 System.exit()
。
编译文件。(有趣的是,javac 不在意它是否在 java.lang
包中)
将该类添加到 JRE 的 rt.jar
中。
现在 JVM 将使用这个新类。(邪恶的笑声)
这是您可能需要了解的一种可能性。它是否是一个好主意,或者甚至是否合法,是另一个问题。
java.lang
中的Java代码呢?是的,有安全检查来防止普通应用程序JAR(等)替换“java.lang.*”等类,但这些必须由类加载器/安全管理器强制执行。(如果您依赖Java编译器执行强制执行,那么相对简单地进行颠覆。) - Stephen C我能想到的另一件事(尽管我不知道如何实现)是在某种调试器中运行您的应用程序。我注意到,我的调试器可以在抛出异常时停止执行。
因此,也许可以实现某种执行环境来实现这一点。
用户@dennie发布了一条评论,这实际上应该是一个单独的答案。较新的JVM功能使此变得容易,具体来说:
-XX:+ExitOnOutOfMemoryError
to exit on OOME, or to crash:
-XX:+CrashOnOutOfMemoryError
你在代码中自行捕获 OOME,并使用 System.exit()
如何?
有一种可能性,我希望能够被说服放弃,那就是创建一个愚蠢的线程,它的工作是在堆上执行某些操作。如果它收到 OOME 错误 - 那么它将退出整个 JVM。
请告诉我这不是明智的做法。
您可以使用MemoryPoolMXBean来在程序超过设置的堆分配阈值时收到通知。
我自己没有使用过它,但是通过设置分配阈值并在收到通知时调用System.exit(),应该可以以这种方式关闭程序。
我能想到的唯一方法就是使用AOP来包装每个方法(注意排除java.*),用try-catch捕获OOME,如果出现这种情况,则记录日志并在catch块中调用System.exit()。
虽然不是我认为优雅的解决方案...