OOME是一类错误,通常你不应该从中恢复.但是如果它被隐藏在一个线程中,或者有人捕获它,那么应用程序可能会进入一个它不会退出的状态,但是没有用处.有关如何防止这种情况的任何建议,即使面对使用可能愚蠢地尝试捕获Throwable或Error/OOME的库?(即您没有直接访问权限来修改源代码)
Mic*_*ale 34
解:
-XX:OnOutOfMemoryError="<cmd args>; <cmd args>"
Run Code Online (Sandbox Code Playgroud)
定义:首次抛出OutOfMemoryError时运行用户定义的命令.(在1.4.2更新12,6中引入)
见http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html
杀死正在运行的进程的示例:
-XX:OnOutOfMemoryError="kill -9 %p"
Run Code Online (Sandbox Code Playgroud)
如果应用程序的JVM中的某些代码确定它想要尝试捕获OOME并尝试恢复,那么(不幸的是)你可以做任何事情来阻止它......除了可能不切实际的AOP英雄,以及绝对不利于您的应用程序的性能和可维护性.除此之外,您可以做的最好的事情是使用"OnOutOfMemoryError"挂钩来拔出JVM上的插件.请参阅上面的答案:https://stackoverflow.com/a/3878199/139985/
基本上,你必须相信其他开发人员不要做愚蠢的事情.你可能不应该试图防范的其他愚蠢的事情包括:
System.exit()深入调用库方法,Thread.stop()和朋友,实际上,在其他人编写的代码中找到这样的问题的方法是使用代码质量检查器,并执行代码审查.
如果问题出现在第三方代码中,请将其报告为BUG(可能是这样),如果他们不同意,请开始寻找备选方案.
对于那些还不知道这一点的人来说,尝试从OOME恢复是个坏主意的原因有很多:
当前线程正在更新一些重要的数据结构时,可能会抛出OOME.在一般情况下,捕获此OOME的代码无法知道这一点,如果它试图"恢复",则存在应用程序将继续使用损害数据结构的风险.
如果应用程序是多线程的,那么OOME也有可能被抛到其他线程上,使得恢复更加困难.
即使应用程序可以在不使数据结构处于不一致状态的情况下进行恢复,恢复可能只会导致应用程序再次跛行几秒钟,然后再次出现OOME.
除非你适当地设置JVM选项,否则几乎耗尽内存的JVM往往花费大量时间进行垃圾收集,徒劳地试图继续这样做.试图从OOME恢复可能会延长痛苦.
从OOME恢复无助于解决根本原因,通常是内存泄漏,设计不当(即内存浪费)数据结构,和/或使用太小的堆启动应用程序.
用户@dennie发表了一条评论,这应该是它自己的答案。较新的 JVM 功能使这变得简单,特别是
-XX:+ExitOnOutOfMemoryError
Run Code Online (Sandbox Code Playgroud)
在 OOME 上退出或崩溃:
-XX:+CrashOnOutOfMemoryError
Run Code Online (Sandbox Code Playgroud)
自 Java 8u92 https://www.oracle.com/java/technologies/javase/8u92-relnotes.html