Catching Java.Lang.Outofmemoryerror

Catching java.lang.OutOfMemoryError?

There are a number of scenarios where you may wish to catch an OutOfMemoryError and in my experience (on Windows and Solaris JVMs), only very infrequently is OutOfMemoryError the death-knell to a JVM.

There is only one good reason to catch an OutOfMemoryError and that is to close down gracefully, cleanly releasing resources and logging the reason for the failure best you can (if it is still possible to do so).

In general, the OutOfMemoryError occurs due to a block memory allocation that cannot be satisfied with the remaining resources of the heap.

When the Error is thrown the heap contains the same amount of allocated objects as before the unsuccessful allocation and now is the time to drop references to run-time objects to free even more memory that may be required for cleanup. In these cases, it may even be possible to continue but that would definitely be a bad idea as you can never be 100% certain that the JVM is in a reparable state.

Demonstration that OutOfMemoryError does not mean that the JVM is out of memory in the catch block:

private static final int MEGABYTE = (1024*1024);
public static void runOutOfMemory() {
MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
for (int i=1; i <= 100; i++) {
try {
byte[] bytes = new byte[MEGABYTE*500];
} catch (Exception e) {
e.printStackTrace();
} catch (OutOfMemoryError e) {
MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage();
long maxMemory = heapUsage.getMax() / MEGABYTE;
long usedMemory = heapUsage.getUsed() / MEGABYTE;
System.out.println(i+ " : Memory Use :" + usedMemory + "M/" +maxMemory+"M");
}
}
}

Output of this code:

1 : Memory Use :0M/247M
..
..
..
98 : Memory Use :0M/247M
99 : Memory Use :0M/247M
100 : Memory Use :0M/247M

If running something critical, I usually catch the Error, log it to syserr, then log it using my logging framework of choice, then proceed to release resources and close down in a clean fashion. What's the worst that can happen? The JVM is dying (or already dead) anyway and by catching the Error there is at least a chance of cleanup.

The caveat is that you have to target the catching of these types of errors only in places where cleanup is possible. Don't blanket catch(Throwable t) {} everywhere or nonsense like that.

Is it possible to catch out of memory exception in java?

It's not an exception; it's an error: java.lang.OutOfMemoryError

You can catch it as it descends from Throwable:

try {
// create lots of objects here and stash them somewhere
} catch (OutOfMemoryError E) {
// release some (all) of the above objects
}

However, unless you're doing some rather specific stuff (allocating tons of things within a specific code section, for example) you likely won't be able to catch it as you won't know where it's going to be thrown from.

Should I catch OutOfMemoryError?

There is perfect sense in having an exception barrier at the very top of your call stack, catching and logging all Throwables. In server-side code this is in fact the norm. If you make sure to catch the OutOfMemoryError only at that level, and not anywhere lower, there is a very large chance that it will not harm your system: as the call stack unwinds, all the objects created to serve the request will become unreachable. Since it is very likely that the OOME occurred precisely in the thread which was inflicting the strongest memory pressure on the system, all that memory will be reclaimed and the rest of the system will be able to breathe again.

Yes, technically there's always a chance to get an OOME inside a finally block, causing a resource leak or worse; or inside some code which was modifying a long-lived, global structure, breaking its invariants, but it is quite unlikely in practice.

When deciding on your policy for OOMEs keep in mind that your application is subject to many unpredictable factors which are more or less likely to deteriorate its stability. OOME is just another point in that spectrum, and typically its risk impact is not particularly high.

Why is java.lang.OutOfMemoryError: Java heap space not caught?

Because OutOfMemoryError is an Error, not an Exception. Since OutOfMemoryError isn't a subclass of Exception, the catch (Exception e) doesn't apply.

OutOfMemoryError does extend Throwable, however, so you should be able to catch it. Here's a SO discussion on when (if ever) you should catch Errors. Generally, since you can't do anything about it, the recommendation is to not bother catching Errors in production code. But given a special case where you're trying to debug what's going on, it might be helpful.

java.lang.OutOfMemoryError Even in a try-catch block?

You did not catch it. OutOfMemoryError is derived from Error, not from Exception. It is an Error because normally an application is not supposed to catch it, there is close to nothing your application can do to recover.

How to avoid catching OutOfMemoryError in java and how to resolve class java.lang.OutOfMemoryError cannot be cast to class java.lang.Exception issue

Errors are not Exceptions.

Assuming that you get the OutOfMemoryError when calling an external service, then you could check if there was an Error before casting the cause to an Exception

 catch (ExecutionException e) {
if (e.getCause() instanceof Error) {
logger.error("Caught Error");
} else {
Exception ex = (Exception)e.getCause();
if(ex instanceof UncategorizedJmsException) {
logger.error(e.getMessage());
} else if(ex instanceof ApplicationException) {
logger.error(e.getMessage());
}
}
}

Java OutOfMemoryError not caught by clauses that catch Error and Throwable

Inside of your exception handler you're trying to allocate the string "OutOfMemoryError=<" + oome + ">", but you're out of memory and so this is probably going to throw another OutOfMemoryError

Trying to understand the Java Out Of Memory Error and catching the throwable

This is the meat of the code:

try {
Integer[] array = new Integer[10000000 * 10000000];
} catch (Throwable e) {
/* ... */
}
int arr[] = new int[100];

According to the output in your question, this is failing in the large allocation, recovering and succeeding with the small allocation.

Why this program is able to run further, even it got out of memory error.

Short answer: because the JVM is designed so that it can recover from OOMEs in most circumstances.

In your example, the first new operator will result in a memory allocation request for a large amount of memory (see below). The memory allocator will notice that the request is larger than what is available. It will then (typically) trigger a full garbage collector to free up as much memory as possible, then repeat the request.

In this example, there is still not enough memory for the very large allocation. The allocator then throws an OutOfMemoryError which is then propagated like any other exception. At this point in time, there will be lots of free memory ... but just not enough for the huge allocation.

Then your code catches the OOME, and tries to allocate a much smaller array. That succeeds, since the memory is available.

Your test application does this sequence repeatedly, and it behaves the same say each time.

Why this program is able to run further, even it got out of memory error.

In your example, the JVM is only "out of memory" for the huge allocation request. For a smaller request, there is no problem.

Note that the huge new did not actually allocate memory. It tested to see if it could do the allocation, and decided it couldn't.


Basically, your "theory" is incorrect. It is however generally a bad idea to attempt to catch and recover from OOMEs. Here are some reasons:

  1. OOMEs are liable to cause threads to terminate unexpectedly, leaving data structures in inconsistent states, notifications that won't be sent and so on. Recovery can be problematic.

  2. If recovery leads to the same request being repeated, you are liable to get the OOME repeated.

  3. If the root cause of the OOME's is a memory leak, then recovering from an OOME is unlikely to fix the memory leak. So recovery leads to the OOMEs increasing in frequency until the system grinds to a halt.

Of course, there are exceptions to all of the above.


There are a couple of other things to note.

  1. Your allocation appears to be requesting an array with 10,000,000 x 10,000,000 elements. However that is not actually what happens. In fact, 10000000 * 10000000 is an int expression. It overflows, and the result is truncated to 276447232. That is still very large, especially because you need to multiply by 8 to get the approximate array size in bytes.

  2. Since your JVM's max heap size is only 1MB, it is likely that the allocator won't bother to run GC. It would make no difference to the outcome. However, if there was any chance that the GC could free enough memory, you can be assured that it will be run before the allocator gives up and throws an OOME.

  3. The JVM's memory manager splits the heap into a number of spaces. The details depend on the GC that you have selected. When a really large object is requested, the allocator has to find a contiguous area of memory that fits in one space. This can be impossible ... even though the aggregate free space should be large enough.

Recover from java.lang.OutOfMemoryError

bro to catch the outofmemoryerror just replace Exception in catch with OutOfMemoryError

catch(OutOfMemoryError e)



Related Topics



Leave a reply



Submit