Is there a way to build a global OutOfMemoryError
Listener for my Java app?
I want to stop the JVM gracefully (try-catch
is not an option) on OOM.
Since an OutOfMemoryError
is normally not caught, one of the simplest approaches would be
Thread.setDefaultUncaughtExceptionHandler((thread,t) -> {
if(t instanceof OutOfMemoryError) {
System.exit(1);
}
});
But in some cases, like actions executed via an ExecutorService
, all throwables get caught automatically. Still, in these cases, there should be some code in your application evaluating the result and handling exceptional cases anyway.
But perhaps, you want to react before it is to late, e.g. to save pending data before there isn’t even enough memory to do that. A solution for that would go into the following direction:
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));
}
}
Unfortunately, there is no way to simply receive a notification when the total heap usage exceeds a threshold, hence, we have to install a threshold on each memory pool supporting it (usually the tenured generation) and re-check the total usage on notification, to trigger a shutdown when the total usage exceeds a threshold.
You can use JVM option
-XX:OnOutOfMemoryError="<cmd args>; <cmd args>"
and execute command of your choice
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With