So OOME is of the class of errors which generally you shouldn't recover from. But if it is buried in a thread, or someone catches it, it is possible for an application to get in a state from which it isn't exiting, but isn't useful. Any suggestions in how to prevent this even in the face of using libraries which may foolishly try to catch Throwable or Error/OOME?
views:
160answers:
11If it's caught, there's nothing really you can do -- whatever is catching it has the opportunity to recover from the exception (maybe by freeing up memory), which is really the point of it in the first place. Why not edit the source code and remake if you have access to it? That's what I'd do :) Unless there's some signing issue. As the other poster suggested (and something I was thinking about initially) AOP on every method call would be the only way to go, but this would be heavy handed and would also mess up the 'good' OOME catchers.
Only thing I can think of is using AOP to wrap every single method (beware to rule out java.*) with a try-catch for OOME and if so, log something and call System.exit() in the catch block.
Not a solution I'd call elegant, though...
If some piece of code in your application decides that it wants to try to catch OOMEs and attempt to recover, there is (unfortunately) nothing you that you can do to stop it ... apart from AOP heroics that are probably impractical, and definitely are bad for your application's performance and maintainability.
Basically, you have to trust other developers not to do stupid things. Other stupid things that you probably shouldn't try to defend against include:
- calling
System.exit()
, - calling
Thread.stop()
and friends, - leaking open streams, database connections and so on,
- spawning lots of threads,
- randomly squashing (i.e. catching and ignoring) exception,
- etc.
In practice, the way to pick up problems like this in code written by other people is to use code quality checkers, and perform code reviews.
For those who don't already know this, there are a number of reason why it is a bad idea to try to recover from an OOME:
The OOME might have been thrown while the current thread was in the middle of updating some important data structure. In the general case, the code that catches this OOME has no way of knowing this, and if it tries to "recover" there is a risk that the application will continue with a damages data structure.
If the application is multi-threaded there is a chance that OOMEs might have been thrown on other threads as well, making recovery even harder.
Even if the application can recover without leaving data structures in an inconsistent state, the recovery may just cause the application to limp along for a few seconds more and then OOME again.
Unless you set the JVM options appropriately, a JVM that has almost run out of memory tends to spend a lot of time garbage collecting in a vain attempt to keep doing. Attempting to recover from OOMEs is likely to prolong the agony.
Recovering from an OOME does nothing to address the root cause which is typically, a memory leak, a poorly designed (i.e. memory wasteful) data structure, and/or launching the application with a heap that is too small.
How about catching OOME yourself in your code and System.exit()
?
One more thing I could think of (although I do not know how to implement it) would be to run your app in some kind of debugger. I noticed, that my debugger can stop the execution when an exception is thrown. :-)
So may be one could implement some kind of execution environment to achieve that.
You can run your java program using Java Service Wrapper with an OutOfMemory Detection Filter. However, this assumes that the "bad people" are nice enough to log the error :)
One possibility, which I would love to be talked out of, is have a stupid thread thats job is to do something on the heap. Should it receive OOME - then it exits the whole JVM.
Please tell me this isn't sensible.
If you don't care much how the system exits as long as it does exit, then passing a -XX:+HeapDumpOnOutOfMemoryError
JVM switch in the startup script/command might work?
You could use the MemoryPoolMXBean to be notified when a program exceeds a set heap allocation threshold.
I haven't used it myself but it should be possible to shut down this way when the remaining memory gets low by setting an allocation threshold and calling System.exit() when you receive the notification.
edit
OutOfMemoryError.java
, addSystem.exit()
in its constructors.compile it. (interestingly javac doesn't care it's in package
java.lang
)add the class into JRE
rt.jar
now jvm will use this new class. (evil laughs)
This is a possibility you might want to be aware of. Whether it's a good idea, or even legal, is another question.
Another approach is to use the flag
-XX:OnOutOfMemoryError="<cmd args>; <cmd args>"
Definition: Run user-defined commands when an OutOfMemoryError is first thrown. (Introduced in 1.4.2 update 12, 6)
See http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html