17

我想检测一个OutOfMemoryError,进行堆转储,然后自动退出 Java 程序。假设我的 JVM 有以下命令行参数:

-XX:OnOutOfMemoryError="kill -9 %p"
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/tmp

哪个先发生?该进程是转储内存然后退出,还是相反?

4

5 回答 5

10

如果您使用的是 OpenJDK,则可以确定何时运行由 -XX:OnOutOfMemoryError 选项设置的命令。

代码取自 OpenJDK 源代码。参见:debug.cpp

void report_java_out_of_memory(const char* message) {
  static jint out_of_memory_reported = 0;

  // A number of threads may attempt to report OutOfMemoryError at around the
  // same time. To avoid dumping the heap or executing the data collection
  // commands multiple times we just do it once when the first threads reports
  // the error.
  if (Atomic::cmpxchg(1, &out_of_memory_reported, 0) == 0) {
    // create heap dump before OnOutOfMemoryError commands are executed
    if (HeapDumpOnOutOfMemoryError) {    
      tty->print_cr("java.lang.OutOfMemoryError: %s", message);
      HeapDumper::dump_heap_from_oome();
    }

    if (OnOutOfMemoryError && OnOutOfMemoryError[0]) {
      VMError err(message);
      err.report_java_out_of_memory();
    }
  }
} 

以防万一一个简短的解释:

  1. 首先检查是否设置了 HeapDumpOnOutOfMemoryError 选项。在这种情况下运行 dump_heap_from_oome()
  2. 其次,如果设置了 OnOutOfMemoryError 选项,请运行 report_java_out_of_memory()

所以,如果你使用的是 OpenJDK,你的进程肯定会转储内存然后退出。

于 2013-10-17T18:16:51.723 回答
8

我宁愿依靠调用更确定性地处理排序的脚本,即

-XX:OnOutOfMemoryError="/<SomeStandardLocation>/heapAndQuit.sh"

heapAndQuit.sh 然后将使用一种方法来查找pid当前进程的。识别 pid 的一种简单方法是使用您的进程正在写入的日志文件位置

lsof | grep /var/tmp/<yourlogfileName> | cut -d " " -f1 | uniq

然后我将使用jmap转储和kill -9随后

于 2013-10-17T18:39:14.867 回答
7

在 Java 版本 8u92 中,VM 参数

  • -XX:+ExitOnOutOfMemoryError
  • -XX:+CrashOnOutOfMemoryError

已添加,请参阅发行说明

ExitOnOutOfMemoryError
启用此选项后,JVM 将在第一次出现内存不足错误时退出。如果您更喜欢重新启动 JVM 实例而不是处理内存不足错误,则可以使用它。

CrashOnOutOfMemoryError
如果启用此选项,当发生内存不足错误时,JVM 会崩溃并生成文本和二进制崩溃文件。

增强请求:JDK-8138745(参数命名错误,虽然 JDK-8154713ExitOnOutOfMemoryError而不是ExitOnOutOfMemory

于 2016-11-24T15:22:21.567 回答
3

你应该使用

ExitOnOutOfMemoryError 或 CrashOnOutOfMemoryError

HeapDumpOnOutOfMemoryError

OpenJDK JVM (Hotspot) 首先进行堆转储,然后按照选择崩溃或退出。

为了更清楚地理解,您可以参考处理此特定逻辑的 JVM 源文件。

https://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/8641949eb21f/src/share/vm/utilities/debug.cpp

于 2019-05-29T06:15:37.787 回答
1

我认为这在很大程度上取决于您使用的实际 JVM 实现。我想相信使用中的 JVM 采用了一些智能排序,首先执行堆转储而不是杀死机器。但是,在我看来,您不应该依赖选项的顺序。

于 2013-10-17T17:57:28.433 回答