有没有办法为我的Java应用程序构建全局OutOfMemoryError
侦听器?
我想在OOM上优雅地停止JVM(try-catch
不是一个选项)。
答案 0 :(得分:13)
答案 1 :(得分:6)
由于OutOfMemoryError
通常没有被捕获,因此最简单的方法之一就是
Thread.setDefaultUncaughtExceptionHandler((thread,t) -> {
if(t instanceof OutOfMemoryError) {
System.exit(1);
}
});
但在某些情况下,就像通过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));
}
}
不幸的是,当总堆使用率超过阈值时,无法简单地接收通知,因此,我们必须在支持它的每个内存池(通常是终身代)上安装阈值并重新检查总使用量通知时,在总使用量超过阈值时触发关闭。
答案 2 :(得分:5)
还有ExitOnOutOfMemoryError option用作JVM命令行选项。
-XX:OnOutOfMemoryError
ExitOnOutOfMemoryError - 启用此选项时,JVM会在第一次出现内存不足错误时退出。如果您更喜欢重新启动JVM实例而不是处理内存不足错误,则可以使用它。
它不是一个优雅的 JVM退出,我不认为关机挂钩运行。