如何监听OutOfMemoryError并退出JVM

rel*_*ood 11 java out-of-memory java-8

有没有办法OutOfMemoryError为我的Java应用程序构建全局侦听器?

我想try-catch在OOM上优雅地停止JVM(不是一个选项).

Jig*_*shi 14

您可以使用JVM选项

-XX:OnOutOfMemoryError="<cmd args>; <cmd args>"
Run Code Online (Sandbox Code Playgroud)

并执行您选择的命令


Hol*_*ger 6

由于OutOfMemoryError通常不会被捕获,因此最简单的方法之一就是

Thread.setDefaultUncaughtExceptionHandler((thread,t) -> {
    if(t instanceof OutOfMemoryError) {
        System.exit(1);
    }
});
Run Code Online (Sandbox Code Playgroud)

但在某些情况下,就像通过a执行的操作一样ExecutorService,所有throwable都会被自动捕获.尽管如此,在这些情况下,应用程序中应该有一些代码可以评估结果并处理特殊情况.

但也许,你想它迟到之前作出反应,例如在没有足够的内存来保存未决数据之前.解决方案将进入以下方向:

MemoryMXBean mBean = ManagementFactory.getMemoryMXBean();
((NotificationEmitter)mBean).addNotificationListener(
    (n, mb) -> {
        MemoryUsage mu = ((MemoryMXBean)mb).getHeapMemoryUsage();
        if(mu.getUsed()*100/mu.getMax() > 80)
            System.out.println("more than 80% used");// may initiate a shut down
    },
    n -> n.getType().equals(MemoryNotificationInfo.MEMORY_COLLECTION_THRESHOLD_EXCEEDED),
    mBean);

for(MemoryPoolMXBean pool : ManagementFactory.getMemoryPoolMXBeans()) {
    if(pool.getType() == MemoryType.HEAP && pool.isCollectionUsageThresholdSupported()) {
        pool.setCollectionUsageThreshold((int)Math.floor(pool.getUsage().getMax()*0.8));
    }
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,当总堆使用率超过阈值时,无法简单地接收通知,因此,我们必须在支持它的每个内存池(通常是终身代)上安装阈值,并重新检查通知的总使用情况,在总使用量超过阈值时触发关闭.


pru*_*nge 5

还有一个ExitOnOutOfMemoryError选项用作JVM命令行选项。

-XX:OnOutOfMemoryError
Run Code Online (Sandbox Code Playgroud)

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

这实际上不是正常的 JVM退出,我认为关闭挂钩不会运行。