It has been said that the great scientific disciplines are examples of giants standing on the shoulders of other giants. It has also been said that the software industry is an example of midgets standing on the toes of other midgets.
- Alan Cooper

the brown-dragon blog

Fast Java Exceptions

2009-01-27

Java Exceptions are notoriously slow. Heck - everything in Java is slow, but exception handling is slow in most languages and doubly slow in Java.

Why is this a problem? Because when coding in Java, exceptions are everywhere you look. Given their profuseness they turn out to be pretty useful beasts. So what can we do to improve their performance?

First, let's start off by trying to figure out what an exception does and why it takes time:

Life Of An Exception

When we examine this flow, it seems pretty clean. Worse, there doesn't seem to be anything we can do to as programmers using the JVM (as opposed to tinkering around with it). However, if we look a bit closer, there is something we can do.

The key here is to notice that the JVM keeps a stack trace of the exception in every throwable object by default. This trace is very useful to the developer when the exception is finally dumped because he/she can trace where the exception came from.

In many cases, however, the exception is caught deep within the code and the developer initiates some flow that allows the user to proceed without core dumping. In all these cases carrying around the stack trace is useless and expensive.

It is, fortunately, easy to ask the JVM to stop gathering this information simply by overriding a method in the base Throwable class.

Here is the code for a "fast exception":

FastEx.java

public class FastEx extends Exception {
    public Throwable fillInStackTrace()
    {
        return null;
    }
}

When testing the fast exception vs normal exceptions I got almost an order-of-magnitude increase in speed!

$time java TestNormEx
real    0m40.262s
user    0m0.031s
sys     0m0.000s

$time java TestFastEx
real    0m4.976s
user    0m0.015s
sys     0m0.015s

The test code follows:

TestNormEx.java

public class TestNormEx
{
    public void somethrow () throws Exception
    {
        throw new Exception ();
    }

    public void somefunc ()
    {
        for (int i = 0;i < 50000000;++i) {
            try {
                somethrow ();
            }
            catch (Exception e) {
                // Do nothing
                // since this is a pure timing test
            }
        }
    }

    public static void main (String args[])
    {
            TestNormEx  t;

        t  =   new TestNormEx ();
        t.somefunc ();
    }
}

TestFastEx.java

public class TestFastEx
{
    public void somethrow () throws FastEx
    {
        throw new FastEx ();
    }

    public void somefunc ()
    {
        for (int i = 0;i < 50000000;++i) {
            try {
                somethrow ();
            }
            catch (FastEx e) {
                // Do nothing
                // since this is a pure timing test
            }
        }
    }

    public static void main (String args[])
    {
            TestFastEx  t;

        t  =   new TestFastEx ();
        t.somefunc ();
    }
}

Other Posts

(ordered by Tags then Date)