Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to listen for OutOfMemoryError and exit the JVM [duplicate]

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.

like image 445
rellocs wood Avatar asked Jan 08 '18 09:01

rellocs wood


2 Answers

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.

like image 157
Holger Avatar answered Oct 20 '22 16:10

Holger


You can use JVM option

-XX:OnOutOfMemoryError="<cmd args>; <cmd args>"

and execute command of your choice

like image 32
jmj Avatar answered Oct 20 '22 17:10

jmj