28

I used to think that it's not, but yesterday I had to do it. It's an application that uses Akka (an actor system implementation for the JVM) to process asynchronous jobs. One of the actors performs some PDF manipulation, and because the library is buggy, it dies with a StackOverflowError every now and then.

The second aspect is that Akka is configured to shutdown its whole actor system if any JVM fatal error (e.g. StackOverflowError) is caught.

The third aspect is that this actor system is embedded inside a web app (for WTF-ish, legacy, reasons), so when the actor system is shut down, the web app is not. The net effect is that on a StackOverflowError our job processing application becomes just an empty web app.

As a quick fix I had to catch the StackOverflowError being thrown, so that the thread pool of the actor system isn't torn down. This lead me to think that maybe it's sometimes okay to catch such errors especially in contexts like this? When there's a thread pool processing arbitrary tasks? Unlike an OutOfMemoryError I can't imagine how a StackOverflowError can leave an application in an inconsistent state. The stack is cleared after such an error, so computation can go on normally. But maybe I'm missing something important.

Also, let it be noted that I'm all for fixing the error in the first place (as a matter of fact I have already fixed an SOE in this same app a few days ago), but I really don't know when this kind of situation might arise.

Why would it be better to restart the JVM process instead of catching the StackOverflowError, mark that job as failed, and continue with my business?

Is there any compelling reason to never catch SOEs? Except "best practices", which is a vague term that tells me nothing.

5
  • 1
    another option would be to increase the stack space available on the JVM Aug 22, 2013 at 7:35
  • 3
    @ratchetfreak: StackOverflowExceptions are usually due to a non-terminating chain of method calls - increasing the stack space would then increase the memory cost of a new thread for no benefit.
    – jhominal
    Aug 22, 2013 at 11:59
  • 1
    At least one SOE was legitimate because the input was very large. Unfortunately, handling it with a recursive implementation (Java's regex impl.) was not a very good idea. Anyway, even when the computation is guaranteed to terminate, you don't know if the new stack size is large enough for other computations. Aug 22, 2013 at 14:35
  • 2
    Shouldn't this be migrated to Sta... Oh, wait... never mind. :-)
    – Blrfl
    Aug 24, 2013 at 12:40
  • Regarding your buggy library. You should really migrate that pdf manipulating function into its own process so you can let the os kill it. Aug 1, 2014 at 20:26

2 Answers 2

45

As a general rule, if it were absolutely never, ever acceptable to do something, and there was agreement about that, the language implementers would not have allowed it. There are almost no such unanimously clear-cut maxims. (Luckily, because that's what keeps us human programmers in jobs!)

It looks very much as if you've found a situation where catching this error is the best option for you: it lets your application work, while all other alternatives don't, and that's what counts in the end. All "best practices" are simply summations of long experiences with many cases that can usually be used in place of a detailed analysis of a specific case to save time; in your case, you've already done the specific analysis and got a different result. Congratulations, you're capable of independent thought!

(That said, surely there are situations where a stack overflow might leave an application inconsistent just like a memory exhaustion. Just imagine that some object is constructed and then initialized with the help of nested internal method calls - if one of them throws, the object may very well be in a state not supposed to be possible, just as if an allocation had failed. But that doesn't mean that your solution couldn't still be the best one.)

3
  • 3
    Thanks. My doubts were somewhat reinforced after I found out that .NET made StackOverflowException a non-catchable exception. I know, it's a different platform, but I thought they might have had a reason. Also, your point with regard to object initialization is spot on. This leads me to think that I should catch this SOE a few abstraction layers below, so that I don't catch the "wrong" SOE. Aug 22, 2013 at 6:33
  • 14
    +1: best practices should always come with explanations why and in what context they are "best", so that you can judge whether they apply to your specific case. Aug 22, 2013 at 10:04
  • situations here should be situations where.
    – Servy
    Aug 23, 2013 at 19:42
2

I don't know if there are any JVM-specific risks here, but overall it seems quite sensible.

For example there are recursive algorithms, like naive quicksort, that have log(n) stack depth in a typical case, but in the worst case they degrade to depth n that can blow up the stack.

The worst case is rare, and unlikely to happen again if you restart sort on the partially-sorted set, so it makes a lot of sense to catch stack overflow exception when it happens and restart work instead of trying to prevent error from happening or killing entire application.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.