我想检测OutOfMemoryError
,进行堆转储,然后自动退出Java程序。假设我的JVM有以下命令行参数:
-XX:OnOutOfMemoryError="kill -9 %p"
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/tmp
首先发生了什么?进程是否会转储内存然后退出,反之亦然?
答案 0 :(得分:9)
如果您使用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();
}
}
}
以防简短说明:
所以,当然,如果您使用OpenJDK,您的进程将转储内存然后退出。
答案 1 :(得分:7)
我宁愿依赖于调用一个更有确定性地处理排序的脚本,即
-XX:OnOutOfMemoryError="/<SomeStandardLocation>/heapAndQuit.sh"
然后 heapAndQuit.sh将使用一种方法来查找当前进程的pid
。
识别pid的一种简单方法是使用进程写入的日志文件位置
lsof | grep /var/tmp/<yourlogfileName> | cut -d " " -f1 | uniq
然后,我将使用jmap
转储并随后kill -9
答案 2 :(得分:4)
在Java版本8u92中,VM参数
-XX:+ExitOnOutOfMemoryError
-XX:+CrashOnOutOfMemoryError
已添加,请参阅release notes。
<强> ExitOnOutOfMemoryError 强>
启用此选项后,JVM将退出 第一次出现内存不足错误。如果你可以使用它 更喜欢重新启动JVM的实例而不是处理掉 记忆错误。<强> CrashOnOutOfMemoryError 强>
如果启用此选项,则启用此选项 发生内存不足错误,JVM崩溃并生成文本和 二进制崩溃文件。
增强请求:JDK-8138745(参数命名错误JDK-8154713,ExitOnOutOfMemoryError
而不是ExitOnOutOfMemory
)
答案 3 :(得分:1)
我认为这在很大程度上取决于您使用的实际JVM实现。我想相信使用的JVM采用了一些智能排序,首先执行堆转储而不是杀死机器。但是,在我看来,你不应该依赖选项的顺序。
答案 4 :(得分:0)
您应使用
ExitOnOutOfMemoryError或 CrashOnOutOfMemoryError
和
HeapDumpOnOutOfMemoryError
OpenJDK JVM(热点)首先进行堆转储,然后崩溃或退出(如所选择的那样)。
为了更清楚地理解,您可以参考JVM源文件来处理这一特定逻辑。
https://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/8641949eb21f/src/share/vm/utilities/debug.cpp