即使坏人试图抓住它,我如何在任何OutOfMemoryException上退出JVM

时间:2010-10-06 09:49:01

标签: java jvm

OOME是一类错误,通常你不应该从中恢复。但是如果它被隐藏在一个线程中,或者有人捕获它,那么应用程序可能会进入一个它不会退出的状态,但是没有用处。有关如何防止这种情况的任何建议,即使面对使用可能愚蠢地尝试捕获Throwable或Error / OOME的库? (即您没有直接访问权限来修改源代码)

10 个答案:

答案 0 :(得分:34)

解决方案:

-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"

答案 1 :(得分:8)

如果你的应用程序的JVM中的某些代码决定它想要捕获OOME并尝试恢复,那么(不幸的是)你可以做任何事情来阻止它...除了可能的AOP英雄之外不切实际,绝对不利于您的应用程序的性能和可维护性。除此之外,您可以做的最好的事情是使用“OnOutOfMemoryError”挂钩来拔出JVM上的插件。请参阅上面的答案:https://stackoverflow.com/a/3878199/139985/

基本上,你必须相信其他开发者不要做愚蠢的事情。你可能不应该试图防范的其他愚蠢的事情包括:

  • 在库方法中深入调用System.exit()
  • 致电Thread.stop()和朋友,
  • 泄漏开放流,数据库连接等,
  • 产生大量线程,
  • 随机挤压(即捕捉和忽略)异常,

在实践中,在其他人编写的代码中解决这类问题的方法是使用代码质量检查器,并执行代码审查。

如果问题出现在第三方代码中,请将其报告为BUG(可能是这样),如果他们不同意,请开始寻找替代方案。


对于那些还不知道这一点的人来说,尝试从OOME恢复是个坏主意有很多原因:

  1. 当前线程正在更新某些重要数据结构时,可能会抛出OOME。在一般情况下,捕获此OOME的代码无法知道这一点,如果它试图“恢复”,则存在应用程序继续使用损害数据结构的风险。

  2. 如果应用程序是多线程的,那么OOME也有可能被抛到其他线程上,使恢复更加困难。

  3. 即使应用程序可以在不使数据结构处于不一致状态的情况下进行恢复,恢复可能只会导致应用程序再次跛行几秒钟,然后再次出现OOME。

  4. 除非你适当地设置JVM选项,否则几乎耗尽内存的JVM往往会花费大量时间进行垃圾收集,徒劳地试图继续这样做。试图从OOME恢复可能会延长痛苦。

  5. 从OOME恢复无法解决根本原因,通常是内存泄漏,设计不当(即内存浪费)数据结构,和/或使用太小的堆启动应用程序。

答案 2 :(得分:2)

  1. 修改OutOfMemoryError.java,添加 System.exit()在其构造函数中。

  2. 编译它。 (有趣的是javac 不关心它在包java.lang

  3. 将课程添加到JRE rt.jar

  4. 现在jvm将使用这个新类。 (邪恶的笑)

  5. 您可能希望了解这种可能性。无论是好主意,还是合法,都是另一个问题。

答案 3 :(得分:1)

我能想到的另一件事(虽然我不知道如何实现它)将是在某种调试器中运行你的应用程序。我注意到,我的调试器可以在抛出异常时停止执行。 : - )

因此可能可以实现某种执行环境来实现这一点。

答案 4 :(得分:1)

用户@dennie发表了评论,这实际上应该是它自己的答案。较新的JVM功能使此操作特别容易

const routes: Routes = [


{ path: '', component: SelectionComponent }
];


@NgModule({
  declarations: [],
  imports: [
    RouterModule.forChild(routes)
  ],
  exports: [
    RouterModule
  ]
})
export class SelectionRoutingModule { }

要退出OOME或崩溃:

-XX:+ExitOnOutOfMemoryError

自Java 8u92 https://www.oracle.com/java/technologies/javase/8u92-relnotes.html

答案 5 :(得分:0)

如何在代码和System.exit()中自己捕获OOME?

答案 6 :(得分:0)

您可以使用Java Service Wrapper使用OutOfMemory Detection Filter来运行您的Java程序。但是,这假设“坏人”足以记录错误:)

答案 7 :(得分:0)

我很乐意谈论的一种可能性是有一个愚蠢的线程,工作就是在堆上做一些事情。如果接收OOME - 那么它将退出整个JVM。

请告诉我这不合情理。

答案 8 :(得分:0)

当程序超过设定的堆分配阈值时,您可以使用MemoryPoolMXBean通知。

我自己没有使用它,但是当通过设置分配阈值并在收到通知时调用System.exit()来剩余内存变低时,应该可以通过这种方式关闭。

答案 9 :(得分:-1)

我唯一能想到的就是使用AOP用OOME的try-catch包装每一个方法(小心排除java。*),如果是这样,记录一下并在catch块中调用System.exit()

虽然不是我称之为优雅的解决方案......