如何监听 OutOfMemoryError 并退出 JVM
How to listen for OutOfMemoryError and exit the JVM
有没有办法为我的 Java 应用构建全局 OutOfMemoryError
侦听器?
我想在 OOM 时优雅地停止 JVM(try-catch
不是一个选项)。
您可以使用JVM option
-XX:OnOutOfMemoryError="<cmd args>; <cmd args>"
并执行您选择的命令
由于 OutOfMemoryError
通常不会被捕获,最简单的方法之一是
Thread.setDefaultUncaughtExceptionHandler((thread,t) -> {
if(t instanceof OutOfMemoryError) {
System.exit(1);
}
});
但在某些情况下,例如通过 ExecutorService
执行的操作,所有可抛出的对象都会被自动捕获。尽管如此,在这些情况下,您的应用程序中仍然应该有一些代码来评估结果并处理异常情况。
但或许,您想在之前做出反应,例如在内存不足之前保存未决数据。解决方案将朝以下方向发展:
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));
}
}
不幸的是,当总堆使用量超过阈值时,无法简单地接收通知,因此,我们必须在支持它的每个内存池(通常是老一代)上安装一个阈值并重新检查总使用量通知,当总使用量超过阈值时触发关闭。
还有 ExitOnOutOfMemoryError option 用作 JVM 命令行选项。
-XX:OnOutOfMemoryError
ExitOnOutOfMemoryError - When you enable this option, the JVM exits on the first occurrence of an out-of-memory error. It can be used if you prefer restarting an instance of the JVM rather than handling out of memory errors.
这不是真正的优雅 JVM 退出,我不认为关闭钩子运行。
有没有办法为我的 Java 应用构建全局 OutOfMemoryError
侦听器?
我想在 OOM 时优雅地停止 JVM(try-catch
不是一个选项)。
您可以使用JVM option
-XX:OnOutOfMemoryError="<cmd args>; <cmd args>"
并执行您选择的命令
由于 OutOfMemoryError
通常不会被捕获,最简单的方法之一是
Thread.setDefaultUncaughtExceptionHandler((thread,t) -> {
if(t instanceof OutOfMemoryError) {
System.exit(1);
}
});
但在某些情况下,例如通过 ExecutorService
执行的操作,所有可抛出的对象都会被自动捕获。尽管如此,在这些情况下,您的应用程序中仍然应该有一些代码来评估结果并处理异常情况。
但或许,您想在之前做出反应,例如在内存不足之前保存未决数据。解决方案将朝以下方向发展:
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));
}
}
不幸的是,当总堆使用量超过阈值时,无法简单地接收通知,因此,我们必须在支持它的每个内存池(通常是老一代)上安装一个阈值并重新检查总使用量通知,当总使用量超过阈值时触发关闭。
还有 ExitOnOutOfMemoryError option 用作 JVM 命令行选项。
-XX:OnOutOfMemoryError
ExitOnOutOfMemoryError - When you enable this option, the JVM exits on the first occurrence of an out-of-memory error. It can be used if you prefer restarting an instance of the JVM rather than handling out of memory errors.
这不是真正的优雅 JVM 退出,我不认为关闭钩子运行。