“-XX:+ExitOnOutOfMemoryError”在“java.lang.OutOfMemoryError: Direct buffer memory”错误上被忽略。

13
如果OutOfMemoryError是由分配直接字节缓冲区引起的,则JVM标志-XX:+ExitOnOutOfMemoryError将被忽略。
在Oracle JDK和OpenJDK上检查 Java版本“1.8.0_144” Java(TM)SE运行时环境(构建1.8.0_144-b01) Java HotSpot(TM) 64位服务器VM(构建25.144-b01,混合模式)
操作系统:Ubuntu 16.04
要重现,请运行以下代码
package com.company;
import java.nio.ByteBuffer;
public class Main {

    public static void main(String[] args) {
        // This should guarantee to throw:            
        try {
            ByteBuffer bb = ByteBuffer.allocateDirect(10485760*2);
            System.out.println("OOME not triggered");
        } catch (OutOfMemoryError err) {                
            System.out.println("OOME didn't terminate JVM!");
        }
    }
}

jvm参数:-XX:MaxDirectMemorySize=10485760 -XX:+ExitOnOutOfMemoryError

程序输出“OOME didn't terminate JVM!”并以退出码0终止。我原本期望它会崩溃并返回大于0的退出码。当由于堆空间不足而抛出OutOfMemory时,它会以这种方式工作。

如果您使用jvm参数-Xmx10485760 -XX:+ExitOnOutOfMemoryError运行以下代码,则jvm进程将以退出码3崩溃:

try {        
    byte[] b = new byte[10485760*2];
    System.out.println("OOME not triggered");
} catch (OutOfMemoryError err) {
    System.out.println("OOME didn't terminate JVM!");
}

上面代码的输出将是: 由于Java堆空间不足而终止:java.lang.OutOfMemoryError 这是预期的行为,但第一个示例没有复现。
如何使ExitOnOutOfMemoryError选项适用于此情况? 也许有更新的JDK或替代JDK实现没有这样的错误?
我在druid.io中遇到了这个问题。如果实时索引任务遇到
java.lang.OutOfMemoryError: Direct buffer memory

它卡住了,无法终止。


不仅应该捕获 OOME,还应该在记录日志后重新抛出它。请编辑上面的代码示例。但是,我确认即使设置了 +ExitOnOutOfMemoryError 标志,Java 也不会在 OOME 抛出时退出。 - Alexander Vasiljev
2
为了演示目的,捕获了OutOfMemory异常。即使用户代码捕获了OutOfMemory异常,由于存在jvm标志-XX:+ExitOnOutOfMemoryError,jvm进程仍应崩溃。在原始帖子中添加了第二个代码示例,重现了这种行为。 - denisvlah
1个回答

5
根据Java问题跟踪器上的讨论,ExitOnOutOfMemoryError仅旨在覆盖JVM本身抛出的OutOfMemory错误。NIO缓冲区是从原生代码中分配的,因此与它们相关的OOM错误也是从原生代码中抛出的,所以不幸的是这似乎是预期的行为。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接