views:

1196

answers:

10

I'm developing a program that would require huge amount of memory, and I want to catch when out-of-memory exception happens. I had heard this is not possible to do, but curious if there is any development on this end.

+12  A: 

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.

ChssPly76
Plus, there's likely no easy way for you to recover from it if you do catch it.
matt b
@matt b - in the specific case where you're **able** to catch it you're presumably trying to control your memory consumption and thus would be able to release some / all of it. But generally speaking you're right, of course.
ChssPly76
A: 

Sure, catching OutOfMemoryError is allowed. Make sure you have a plan for what to do when it happens. You will need to free up some memory (by dropping references to objects) before allocating any more objects, or you will just run out of memory again. Sometimes the mere act of unwinding the stack a few frames will do that for you, some times you need to do something more explicit.

Keith Randall
+6  A: 

It's possible:

try {
   // tragic logic created OOME, but we can blame it on lack of memory
} catch(OutOfMemoryError e) {
   // but what the hell will you do here :)
} finally {
   // get ready to be fired by your boss
}
Suraj Chandran
There *is* at least one reasonable thing which you could be doing which causes an OOME and is recoverable: Loading a very large image. The only thing in the try block is a call to ImageIO.read(), and you're showing the user a dialog telling them that the image is too large in the catch block. Just saying...
uckelman
@uckleman....i guess you are right, but my system architects don't leave any scope fo arguments....hence the "get ready to be fired by your boss" stuff :)
Suraj Chandran
A: 

It is possible to catch Any exception. Just write

try{
   // code which you think might throw exception
}catch(java.lang.Throwable t){
   // you got the exception. Now what??
}

Ideally you are not supposed to catch java.lang.Error exceptions. Not catching such exceptions, and letting the application to terminate might be the best solution when they occur. If you think that you can very well handle such Error's, then go ahead.

HanuAthena
+1  A: 

It is possible, but if you run out of heap its not very useful. If there are resources which can be freed you better off using SoftReference or WeakReference to such resources and their clean-up will be automatic.

I have found it useful if you run out of direct memory before this doesn't trigger a GC automatically for some reason. So I have had cause to force a gc if I fail to allocate a direct buffer.

Peter Lawrey
+4  A: 

You can catch and attempt to recover from OutOfMemoryError (OOM) exceptions, but it is probably a bad idea ... especially if your aim is for the application to "keep going".

There are a number of reasons for this:

  1. As others have pointed out, there are better ways to manage memory resources than explicitly freeing things; i.e. using SoftReference and WeakReference for objects that could be freed if memory is short.

  2. If you wait until you actually run out of memory before freeing things, your application is likely to spend more time running the garbage collector. Depending on your JVM version and on your GC tuning parameters, the JVM can end up running the GC more and more frequently as it approaches the point at which will throw an OOM. The slowdown (in terms of the application doing useful work) can be significant. You probably want to avoid this.

  3. If the root cause of your problem is a memory leak, then the chances are that catching and recovering from the OOM will not reclaim the leaked memory. You application will keep going for a bit then OOM again, and again, and again at ever reducing intervals.

So my advice is NOT attempt to keep going from an OOM ... unless you know why it happened and know that your recovery will release enough memory to continue.

Stephen C
A: 

As a digression - why does your application run out of memory?

Why not post a follow up question asking how to restructure the application to use less memory?

Fortyrunner
+1  A: 

just throwing this out there for all those who ponder why someone might be running out of memory: i'm working on a project that runs out of memory frequently and i have had to implement a solution for this.

the project is a component of a forensics and investigation app. after collecting data in the field (using very low memory footprint, btw) data is opened in our investigation app. one of the features is to perform a CFG traversal of any arbitrary binary image that was captured in the field (applications from physical memory). these traversals can take a long time, but produce very helpful visual representations of the binary that was traversed.

to speed the traversal process, we try to keep as much data in physical memory as possible, but the data structures grow as the binary grows and we cannot keep it ALL in memory (the goal is to use a java heap less than 256m). so what do i do?

i created disk-backed versions of LinkedLists, Hashtables, etc. these are drop-in replacements for their counterparts and implement all the same interfaces so they look identical from the outside world.

the difference? these replacement structures cooperate with each other, catching out of memory errors and requesting that the least recently used elements from the least recently used collection be freed from memory. freeing the element dumps it to disk in temporary file (in the system provided temp directory) and marks a placeholder objects as "paged-out" in the proper collection.

there are PLENTY of reasons you might run out of memory in a java app - the root of most of these reasons is either one or both of: 1. App runs on a resource constrained machine (or attempts to limit resource usage by limiting heap size) 2. App simply requires large amounts of memory (image editing was suggested, but how about audio and video? what about compilers like in my case? how about long-term data collectors without non-volatile storage?)

-bit

bitflung
+1  A: 

It is possible to catch an OutOfMemoryError (It's an Error, not an Exception), but you should be aware, that there is no way to get a defined behaviour.
You may even get another OutOfMemoryError while trying to catch it.

So the better way is to create/use memory aware Caches. There are some frameworks out there (example: JCS), but you can easily build your own by using SoftReference. There is a small article about how to use it here. Follow the links in the article to get more informations.

Hardcoded
A: 

There is probably at least one good time to catch an OutOfMemoryError, when you are specifically allocating something that might be way too big:

public static int[] decode(InputStream in, int len) throws IOException {
  int result[];
  try {
    result = new int[len];
  } catch (OutOfMemoryError e) {
    throw new IOException("Result too long to read into memory: " + len);
  } catch (NegativeArraySizeException e) {
    throw new IOException("Cannot read negative length: " + len);
  }
  ...
}
Adam Goode