tags:

views:

316

answers:

4

I know that exceptions have a performance penalty, and that it's generally more efficient to try and avoid exceptions than to drop a big try/catch around everything -- but what about the try block itself? What's the cost of merely declaring a try/catch, even if it never throws an exception?

+10  A: 

The performance cost of try is very small. The major cost of exception handling is getting the stack trace and other metadata, and that's a cost that's not paid until you actually have to throw an exception.

But this will vary by language and implementation. Why not write a simple loop in C# and time it yourself?

JSBangs
Yep. Try is effectively free because it's basically handled by metadata that's really only inspected when the exception is actually thrown.
Curt Hagenlocher
+2  A: 

You might want to read up on Structured Exception Handling. It's Window's implementation of exceptions and used in .NET.

http://www.microsoft.com/msj/0197/Exception/Exception.aspx

Unknown
+2  A: 

A common saying is that exceptions are expensive when they are caught - not thrown. This is because most of the exception metadata gathering (such as getting a stack trace etc.) only really happens on the try-catch side (not on the throw side).

Unwinding the stack is actually pretty quick - the CLR walks up the call stack and only pays heed to the finally blocks it finds; at no point in a pure try-finally block does the runtime attempt to 'complete' an exception (it's metadata etc.).

From what I remember, any try-catches with filters (such as "catch (FooException) {}") are just as expensive - even if they do not do anything with the exception.

I would venture to say that a method (call it CatchesAndRethrows) with the following block:

try
{
    ThrowsAnException();
}
catch
{
    throw;
}

Might result in a faster stack walk in a method - such as:

try
{
    CatchesAndRethrows();
}
catch (Exception ex) // The runtime has already done most of the work.
{
    // Some fancy logic
}

Some numbers:

With: 0.13905ms
Without: 0.096ms
Percent difference: 144%

Here is the benchmark I ran (remember, release mode - run without debug):

    static void Main(string[] args)
    {
        Stopwatch withCatch = new Stopwatch();
        Stopwatch withoutCatch = new Stopwatch();

        int iterations = 20000;

        for (int i = 0; i < iterations; i++)
        {
            if (i % 100 == 0)
            {
                Console.Write("{0}%", 100 * i / iterations);
                Console.CursorLeft = 0;
                Console.CursorTop = 0;
            }

            CatchIt(withCatch, withoutCatch);
        }

        Console.WriteLine("With: {0}ms", ((float)(withCatch.ElapsedMilliseconds)) / iterations);
        Console.WriteLine("Without: {0}ms", ((float)(withoutCatch.ElapsedMilliseconds)) / iterations);
        Console.WriteLine("Percent difference: {0}%", 100 * withCatch.ElapsedMilliseconds / withoutCatch.ElapsedMilliseconds);
        Console.ReadKey(true);
    }

    static void CatchIt(Stopwatch withCatch, Stopwatch withoutCatch)
    {
        withCatch.Start();

        try
        {
            FinallyIt(withoutCatch);
        }
        catch
        {
        }

        withCatch.Stop();
    }

    static void FinallyIt(Stopwatch withoutCatch)
    {
        try
        {
            withoutCatch.Start();
            ThrowIt(withoutCatch);
        }
        finally
        {
            withoutCatch.Stop();
        }
    }

    private static void ThrowIt(Stopwatch withoutCatch)
    {
        throw new NotImplementedException();
    }
Jonathan C Dickinson
+3  A: 

Actually, a couple months ago I was creating an ASP.NET web app, and I accidentally wrapped a try / catch block with a very long loop. Even though the loop wasn't generating every exceptions, it was taking too much time to finish. When I went back and saw the try / catch wrapped by the loop, I did it the other way around, I wrapped the loop IN the try / catch block. Performance improved a LOT. You can try this on your own: do something like

int total;

DateTime startTime = DateTime.Now;

for(int i = 0; i < 20000; i++)
{
try
{
total += i;
}
catch
{
// nothing to catch;
}
}

Console.Write((DateTime.Now - startTime).ToString());

And then take out the try / catch block. You'll see a big difference!

Carlo
Hmmm. I just tried this on .Net 2.0 (using a `Stopwatch`). 50000 trials of 20000 loop iterations takes 4184ms without `try-catch`, 4363ms with `try-catch`. That is an incredibly small difference. Such a difference will be even less visible if each iteration is actually doing something beyond a simple addition operation. I hit similar results with and without debugging.
Brian