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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3871278/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 03:46:53  来源:igfitidea点击:

How do I make the JVM exit on ANY OutOfMemoryException even when bad people try to catch it

javajvm

提问by Michael Neale

An OOME is of the class of errors which generally you shouldn't recover from. But if it is buried in a thread, or someone catches it, it is possible for an application to get in a state from which it isn't exiting, but isn't useful. Any suggestions in how to prevent this even in the face of using libraries which may foolishly try to catch Throwable or Error/OOME? (ie you don't have direct access to modify the source code)

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

回答by Michael Neale

Solution:

解决方案:

-XX:OnOutOfMemoryError="<cmd args>; <cmd args>"

Definition: Run user-defined commands when an OutOfMemoryError is first thrown. (Introduced in 1.4.2 update 12, 6)

定义:首次抛出 OutOfMemoryError 时运行用户定义的命令。(在 1.4.2 更新 12、6 中引入)

See http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html

参见http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html

An example that kills the running process:

杀死正在运行的进程的示例:

-XX:OnOutOfMemoryError="kill -9 %p"

回答by Stephen C

If some piece of code in your application's JVM decides that it wants to try to catch OOMEs and attempt to recover, there is (unfortunately) nothing you that you can do to stop it ... apart from AOP heroics that are probably impractical, and definitely are bad for your application's performance and maintainability. Apart from that, the best you can do is to pull the plug on the JVM using an "OnOutOfMemoryError" hook. See the answer above: https://stackoverflow.com/a/3878199/139985/

如果您的应用程序的 JVM 中的某段代码决定尝试捕获 OOME 并尝试恢复,那么(不幸的是)您无法阻止它......除了可能不切实际的 AOP 英雄,并且绝对不利于您的应用程序的性能和可维护性。除此之外,您能做的最好的事情就是使用“OnOutOfMemoryError”钩子拔掉 JVM 上的插头。看上面的答案:https: //stackoverflow.com/a/3878199/139985/

Basically, you have to trust other developers not to do stupid things. Other stupid things that you probably shouldn't try to defend against include:

基本上,您必须相信其他开发人员不会做愚蠢的事情。您可能不应该尝试防御的其他愚蠢的事情包括:

  • calling System.exit()deep in a library method,
  • calling Thread.stop()and friends,
  • leaking open streams, database connections and so on,
  • spawning lots of threads,
  • randomly squashing (i.e. catching and ignoring) exception,
  • etc.
  • System.exit()在库方法中调用深层,
  • 打电话Thread.stop()和朋友,
  • 泄漏打开的流、数据库连接等,
  • 产生大量线程,
  • 随机挤压(即捕捉和忽略)异常,
  • 等等。

In practice, the way to pick up problems like this in code written by other people is to use code quality checkers, and perform code reviews.

在实践中,在其他人编写的代码中发现此类问题的方法是使用代码质量检查器,并进行代码。

If the problem is in 3rd-party code, report it as a BUG (which it probably is) and if they disagree, start looking for alternatives.

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



For those who don't already know this, there are a number of reason why it is a bad idea to try to recover from an OOME:

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

  1. The OOME might have been thrown while the current thread was in the middle of updating some important data structure. In the general case, the code that catches this OOME has no way of knowing this, and if it tries to "recover" there is a risk that the application will continue with a damages data structure.

  2. If the application is multi-threaded there is a chance that OOMEs might have been thrown on other threads as well, making recovery even harder.

  3. Even if the application can recover without leaving data structures in an inconsistent state, the recovery may just cause the application to limp along for a few seconds more and then OOME again.

  4. Unless you set the JVM options appropriately, a JVM that has almost run out of memory tends to spend a lot of time garbage collecting in a vain attempt to keep doing. Attempting to recover from OOMEs is likely to prolong the agony.

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

  2. 如果应用程序是多线程的,则 OOME 可能也会被其他线程抛出,从而使恢复变得更加困难。

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

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

Recovering from an OOME does nothing to address the root cause which is typically, a memory leak, a poorly designed (i.e. memory wasteful) data structure, and/or launching the application with a heap that is too small.

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

回答by irreputable

  1. edit OutOfMemoryError.java, add System.exit()in its constructors.

  2. compile it. (interestingly javac doesn't care it's in package java.lang)

  3. add the class into JRE rt.jar

  4. now jvm will use this new class. (evil laughs)

  1. 编辑OutOfMemoryError.java,添加 System.exit()其构造函数。

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

  3. 将类添加到 JRE rt.jar

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

This is a possibility you might want to be aware of. Whether it's a good idea, or even legal, is another question.

这是您可能想知道的一种可能性。这是否是一个好主意,甚至是否合法,则是另一个问题。

回答by DerMike

One more thing I could think of (although I do not know how to implement it) would be to run your app in some kind of debugger. I noticed, that my debugger can stop the execution when an exception is thrown. :-)

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

So may be one could implement some kind of execution environment to achieve that.

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

回答by dogbane

You can run your java program using Java Service Wrapperwith an OutOfMemory Detection Filter. However, this assumes that the "bad people" are nice enough to log the error :)

您可以使用带有OutOfMemory 检测过滤器的Java Service Wrapper运行您的 java 程序。但是,这假设“坏人”足够好以记录错误:)

回答by Michael Neale

One possibility, which I would love to be talked out of, is have a stupid thread thats job is to do something on the heap. Should itreceive OOME - then it exits the whole JVM.

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

Please tell me this isn't sensible.

请告诉我这是不明智的。

回答by josefx

You could use the MemoryPoolMXBeanto be notified when a program exceeds a set heap allocation threshold.

您可以使用MemoryPoolMXBean在程序超过设置的堆分配阈值时收到通知。

I haven't used it myself but it should be possible to shut down this way when the remaining memory gets low by setting an allocation threshold and calling System.exit() when you receive the notification.

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

回答by Adam Schmideg

How about catching OOME yourself in your code and System.exit()?

自己在代码中捕获 OOME 怎么样System.exit()

回答by biasedbit

Only thing I can think of is using AOP to wrap every single method (beware to rule out java.*) with a try-catch for OOME and if so, log something and call System.exit() in the catch block.

我唯一能想到的是使用 AOP 将每个方法(注意排除 java.*)与 OOME 的 try-catch 包装起来,如果是这样,请记录一些内容并在 catch 块中调用 System.exit()。

Not a solution I'd call elegant, though...

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