To blog Previous post | Next post

On a quest for missing stacktraces

One comment to our recent blog post brought back some memories about a specific experience. The type of experience I wish I had not experienced. Long time before we founded Plumbr I was debugging an application that gave me an exception every once in a blue moon. The level of detail was astounding:

java.lang.NullPointerException

That was it – no stacktrace to work with. And the application was guarded by a truly evil sysadmin who would not let me within 100 yards from the deployment. So the stage was set for numerous all-nighters trying to understand what was causing the error. I bet most of our readers know what I am talking about here.

The first suspect was obvious. The summer intern who never really got exception handling and who could have easily swallowed the exception instead of rethrowing or proper logging. So I was expecting to find something like this in the code somewhere:

System.out.println(e);

But no matter how thoroughly I grep’ed through my source code I could not find anything resembling such carelessness. I do not recall much from the following day besides answering a phone call every few hours and giving the “progress report”. Unfortunately the progress was nowhere in sight. Unless I would count in the numerous updates done to production in a desperate attempt of getting something a bit more meaningful about the possible causes.

But I do remember my faith in Java being tested when I started suspecting something I had always thought being impossible. Namely that Java is capable of literally eating your Exception stacktraces.

And indeed the JIT can and will do it. Need proof? Run the following code:

for (int i = 0; i < 100_000; i++) { try { args[0].toString(); } catch (Exception e) { if (e.getStackTrace().length == 0) { System.out.format("Java ate my stacktrace after iteration #%d %n", i); break; } } }

In my MB Pro equipped with the latest stable JDK 7 hotspot the exception stacktrace gets eaten at the iteration #12,288. But why on earth is this happening and how could one avoid it?

The simple answer is that it is one of the JIT optimizations applied during runtime. As one of our recent posts described, creating Exceptions is darn expensive. So, for performance purposes, when the JIT discovers that an exception is being thrown several times, the code may be recompiled. After recompilation, the compiler may choose a faster tactic using preallocated exceptions that do not provide a stack trace.

Hopefully the vast majority of you will never have to deal with a situation like this. After all, when exceptions are created at the pace triggering JIT to switch to preallocated exceptions, you must be doing something else wrong. After all, exceptions should occur only on exceptional situations.

But for those who do, the solution is simple. You can disable the use of preallocated exceptions by adding -XX:-OmitStackTraceInFastThrow to your JVM startup parameters. So did I and found the culprit after the next JVM restart.

If you liked the blog post, you could consider subscribing to our Twitter feed. I promise to keep the marketroids away from this blog for as long as I possibly can. And keep providing interesting insights from the Java performance landscape.