Performance Implications of try/catch/finally

The accepted wisdom regarding performance of try/catch|finally in C# has normally been: try has no performance side-effects unless an exception is thrown.

A discussion I was involved in recently caused me to discover some performance implications of try/catch blocks. The discussion revolved around protecting the volatility of certain members and the cross-thread memory ordering rules during run-time and during just-in-time compilation.  As it turns out, Microsoft’s x86 .NET 2.0 just-in-time compiler disables optimizations that would affect the CIL order of read/writes in protected blocks (AKA “protected regions”, “guarded blocks”, or “try blocks”).  As a result no optimizations are performed in try blocks.

As it turns out, there are performance side-effects to try/catch even if no exceptions are thrown.  In the following academic example:

    int count = 1;
    SomeMethod();
    count++;
    SomeOtherMethod();
    count++;
    Console.WriteLine(count);

The x86 just-in-time compiler will effectively optimize this as follows:

    SomeMethod();
    SomeOtherMethod();
    Console.WriteLine(3);

The end-result is the same but the side-effects (that would normally be only visible in a debugger) are different (e.g. count never has the value 2).  The just-in-time compiler can do this because it knows no other code can see count when it has the value 2.

Now, wrapping this in a try block, as follows:

    int count = 1;
    try
    {
        SomeMethod();
        count++;
        SomeOtherMethod();
        count++;
    }
    finally
    {
        Console.WriteLine(count);
    }

...is not optimized.  count will be created, it will have the value 1, it will have the value 2 after the call to SomeMethod, it will have the value 3 after SomeOther method, and will have the value 3 when Console.WriteLine is called.  There are two increments that therefore must be performed that are a waste of cycles.

So, be careful how you write code in try blocks.

Published Friday, June 22, 2007 12:38 PM by PeterRitchie

Comments

# re: Performance Implications of try/catch/finally

As always excellent tidbit.  I've been reading your blog and reading your e-mails on Developmentor's .NET lists and I must say I learn from you every week.  Thanks for keeping it interesting and keep up the good work :)

Friday, June 22, 2007 4:21 PM by Peter (Not Richie)

# re: Performance Implications of try/catch/finally

Is the effect, loss of optimization, the same if you move the scope of the try/catch to an outside method calling a function which has the code...or at what point, if any does, optimization come back into play?

Friday, June 22, 2007 8:15 PM by OmegaMan

# re: Performance Implications of try/catch/finally

@OmegaMan: I'm finding it's not as cut-and-dry as "no optimizations are performed".  To a certain extent it depends on what is and isn't in the try block.  It appears a more accurate statement would be "no optimizations are performed that would affect reordering of reads/writes of variables used inside AND outside the try block"; but, I'm following up on that.

Saturday, June 23, 2007 9:26 AM by PeterRitchie

# Performance Implications of try/catch/finally, Part Two

In a previous blog entry Performance Implications of try/catch/finally I outlined that the conventional

Friday, July 13, 2007 10:44 AM by Peter Ritchie's MVP Blog

# Exception Logging

There is often a requirement for an application to log unhandled (and sometimes "handled")

Wednesday, August 01, 2007 9:52 PM by Peter Ritchie's MVP Blog

# re: Performance Implications of try/catch/finally

Does this mean that locked code is not optomized? e.g:

Lock(this)

{

   SomeMethod();

   count++;

   SomeOtherMethod();

   count++;

   Console.WriteLine(count);

}

Wednesday, January 16, 2008 2:00 PM by Jesse

# re: Performance Implications of try/catch/finally

Yes, lock uses try/catch, it will have the same performance implications.

Wednesday, January 16, 2008 8:22 PM by PeterRitchie

# re: Performance Implications of try/catch/finally

Theoretically the try part of this try statement doesn't have to disable optimization, but the finally part has to disable (to some extent) optimization of the try part.  The reason is that the finally part fetches the value of count.

As an analogy, suppose you compare two programs, one with trivial uses of count the way your first program did, and the other one with a for loop and a call to some function with count as an argument in that function call.  Would you say that the for loop causes the decrease in optimization, or would you say that passing count as an argument causes the decrease in optimization?

Thursday, October 02, 2008 11:45 PM by Norman Diamond

# re: Performance Implications of try/catch/finally

@Norman.  Yes, due to various guarantees it has to disable *some* optimizations in the try block.

For example:

try

{

i = 1;

i = 2;

methodThatMightThrow();

i = 3;

Trace.WriteLine(i);

}

catch(Exception)

{

}

Trace.WriteLine(i);

The compiler/runtime guarantees that the state of i will be 2 when the exception is thrown (and that i will be 1 if an exception occurs before setting it to 2--remember there are asynchronous exceptions).  Normal optimizations would think that i only ever really needs to be 3 and would optimize as such.

See also msmvps.com/.../performance-implications-of-try-catch-finally-part-two.aspx

Friday, October 03, 2008 9:05 AM by PeterRitchie

# re: Performance Implications of try/catch/finally

Peter,

Thanks for helping me understand one of the often ignored costs of throwing exceptions. I think too often we ignore the fact that what we write and the bytecode are not exactly the same thing.

Thursday, October 23, 2008 10:43 PM by Esteban Araya

Leave a Comment

(required) 
(required) 
(optional)
(required)