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 Fri, Jun 22 2007 12:38 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

# re: Performance Implications of try/catch/finally

In a business layer where we are searching for records is there much of a performace hit to throw a custom exception like ProductNotonFileException instead of null for example.

Thursday, March 26, 2009 6:23 PM by Eugen

# re: Performance Implications of try/catch/finally

@Eugen.  I prefer returning null for "search-like" method.  I would to performance tests specifically in your circumstance; but my tests show that throwing/catching an exception over returning null is only about 5% slower.  If you don't plan on throwing many exceptions, the difference is essentially negligible.

Friday, March 27, 2009 10:02 AM by PeterRitchie

# re: Performance Implications of try/catch/finally

It's not just that the jitter doesn't optimize away the count variable entirely, it would be illegal to.  It's possible for the output of the second program to be "1", "2" or "3", depending on which (if any) function calls throw an exception.  This makes it a fundamentally different program from the first (which will output "3" when it outputs anything).  The moral of the story isn't that you should be wary of losing optimization opportunities, it's that you should understand what try/finally does and use it properly.

It would be interesting if there were other *legal* optimizations that aren't made, but your example doesn't show this.

Saturday, September 19, 2009 10:12 AM by bmm6o

# re: Performance Implications of try/catch/finally

Do we want this code optimised, though? The coding suggests that if SomeMethod fails, we want count == 2, and if SomeOtherMethod fails, we want count == 3.

Saturday, September 19, 2009 10:29 AM by D

# re: Performance Implications of try/catch/finally

Um, you really should consider removing this post. It would be bad enough if a newbie spouted off such nonsense, but as a MVP it is just disgraceful.

Saturday, September 19, 2009 1:11 PM by Jonathan Allen

# re: Performance Implications of try/catch/finally

@d * @bmm60  Exactly, we don't want it to optimise this code.  The point of the post is to dispel the conventional wisdom that using try/catch does not impact performance; this shows that it does.

Saturday, September 19, 2009 2:50 PM by PeterRitchie

# re: Performance Implications of try/catch/finally

@Jonathan Allen:   In what way do you think this is nonsense?

Saturday, September 19, 2009 2:50 PM by PeterRitchie

# re: Performance Implications of try/catch/finally

@Peter  The examples are two different programs.  They have different outputs depending on when an exception is thrown.  They are not the same and thus the optimizations are not the same.  If you wanted to point out that similar programs with different output might have different runtime performance, then keep the article.  But, it does not prove anything about the lack of optimizations in a try/catch/finally block.    

Saturday, September 19, 2009 3:54 PM by foobar

# re: Performance Implications of try/catch/finally

If I can summarize, I think the criticisms between your non-try code and your try-blocked code is that they're not really functional equivalents.  I'm a linguist, not a computer-scientists so I apologize if the jargon is off -- but in the non-try code, the value of the variable inside WriteLine is always 3 regardless of what happens with the other functions being called.

The JIT-compiled code is -- absolutely and of course -- different between the two because the try-blocked code has not one but THREE potential outcomes:

   int count = 1;

   try

   {

       SomeMethod();  ## Raise exception here count=1

       count++;

       SomeOtherMethod(); ## Raise exception here count=3

       count++;

   }

The functionally-equivalent code, then, is not something that runs two functions and makes count == 3, but rather, the possibility of a raised exception means that there are two implicit conditionals within the try block where there are not within the non-try-block'd code.

So in order to instantiate the conditionals implied within the try block due to the raised exception, you'd have to do something like:

int count = 1;

if someMethod(){

   count++

   if someOtherMethod(){

       count++}

   }

Console.WriteLine(count);

I guess I'd be curious to know: is there a performance difference between THAT and the try-finally code?

Saturday, September 19, 2009 6:28 PM by Chuck

# re: Performance Implications of try/catch/finally

@foobar,that's kind of the point.  How do you show how using try/catch affects performance if you don't have "two programs"?

Sunday, September 20, 2009 12:12 PM by PeterRitchie

# re: Performance Implications of try/catch/finally

@Chuck.  That's the point; the mere introduction of a try block now means there are three explicit potential outcomes.  Previously they where only implicit and could be optimized away because they were implicit.  The only difference between the two snippets of code is the try/catch.  Thus, "using try/catch does not affect performance" is not true (the point of the post).

Sunday, September 20, 2009 12:14 PM by PeterRitchie

# re: Performance Implications of try/catch/finally

Thanks for appropriately reading thru the typos in my post :)

On further review, I see all that should've been clear, but I thank you also for accommodating me in my paraphrase of your point.

Tuesday, September 22, 2009 12:39 AM by Chuck

# re: Performance Implications of try/catch/finally

> The point of the post is to dispel the conventional wisdom that using try/catch does not impact performance; this shows that it does.

I disagree.  This article shows that changing the requirements of a program can result in an implementation that has different performance characteristics.  Moving the WriteLine to the finally block means you're comparing apples to oranges; the programs aren't interchangeable implementations of the same spec, one using try/finally and the other not, they implement different specifications.

I mean, it's true that the second program can't be optimized in the same way that the first one can.  I think it's invalid to draw general conclusions about that from this example.  What if you rewrite it in the style Norman suggests?

Thursday, September 24, 2009 12:00 AM by bmm6o

# re: Performance Implications of try/catch/finally

@bmm60:  The point of the article *is* to show that using try/catch does impact performance.  What you take out of the post, is up to you.  How, otherwise, would you show that try/catch does affect performance if you don't show the analysis of two different snippets of code--that differ only by the addition of a try/catch?  

It's true that the second can't be optimized the same as the first; but that's because of the added try/catch (or try/finally in C#).

Changing the code to what Norman suggests (i.e. comparing linear code to looping code with a try/catch) most certainly would be comparing apples to oranges.  It would then be the very post you're saying it already is.  It wouldn't tell you anything--you couldn't see the difference in optimizations of the same code with and without a container try/catch.

The code *could* use a catch block and push the WriteLine outside the try/catch; but, it would show the same thing without adding any clarity, IMO.

Thursday, September 24, 2009 8:52 AM by PeterRitchie

Leave a Comment

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