Why are try blocks expensive?

.NetCoding Style

.Net Problem Overview


I've heard the advice that you should avoid try catch blocks if possible since they're expensive.

My question is specifically about the .NET platform: Why are try blocks expensive?

Summary of Responses:

There are clearly two camps on this issue: those that say that try blocks are expensive, and those that say "maybe a tiny little bit".

Those that say try blocks are expensive normally mention the "high cost" of unwinding the call stack. Personally, I'm not convinced by that argument - specially after reading about how exceptions handlers are stored here.

Jon Skeet sits on the "maybe a tiny little bit" camp, and has written two articles on exceptions and performance which you can find here.

There was one article that I found extremely interesting: it talked about "other" performance implications of try blocks (not necessarily memory or cpu consumption). Peter Ritchie mentions that he found that code inside try blocks is not optimized as it'd otherwise be by the compiler. You can read about his findings here.

Finally, there's a blog entry about the issue from the man that implemented exceptions in the CLR. Go take a look at Chris Brumme's article here.

.Net Solutions


Solution 1 - .Net

It's not the block itself that's expensive, and it's not even catching an exception, per se, that's expensive, it's the runtime unwinding the call stack until it finds a stack frame that can handle the exception. Throwing an exception is pretty light weight, but if the runtime has to walk up six stack frames (i.e. six method calls deep) to find an appropriate exception handler, possibly executing finally blocks as it goes, you may see a noticeable amount of time passed.

Solution 2 - .Net

You shouldn't avoid try/catch blocks as that generally means you aren't properly handling exceptions that might occur. Structured Exception Handling (SEH) is only expensive when an exception actually occurs as the runtime must walk the call stack looking for a catch handler, execute that handler (and there may be more than one), then execute the finally blocks, and then return control back to the code at the right location.

Exceptions are not intended to be used to control program logic, but rather to indicate error conditions.

> One of the biggest misconceptions > about exceptions is that they are for > “exceptional conditions.” The reality > is that they are for communicating > error conditions. From a framework > design perspective, there is no such > thing as an “exceptional condition”. > Whether a condition is exceptional or > not depends on the context of usage, > --- but reusable libraries rarely know how they will be used. For example, > OutOfMemoryException might be > exceptional for a simple data entry > application; it’s not so exceptional > for applications doing their own > memory management (e.g. SQL server). > In other words, one man’s exceptional > condition is another man’s chronic > condition. > [http://blogs.msdn.com/kcwalina/archive/2008/07/17/ExceptionalError.aspx]

Solution 3 - .Net

A try block is not expensive at all. Little or no cost is incurred unless an exception is thrown. And if an exception has been thrown, that's an exceptional circumstance and you don't care about performance any more. Does it matter if your program takes 0.001 seconds or 1.0 seconds to fall over? No, it does not. What matters is how good the information reported back to you is so you can fix it and stop it happening again.

Solution 4 - .Net

I think people really overestimate the performance cost of throwing exceptions. Yes, there's a performance hit, but it's relatively tiny.

I ran the following test, throwing and catching a million exceptions. It took about 20 seconds on my Intel Core 2 Duo, 2.8 GHz. That's about 50K exceptions a second. If you're throwing even a small fraction of that, you've got some architecture problems.

Here's my code:

using System;
using System.Diagnostics;

namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            Stopwatch sw = Stopwatch.StartNew();
            for (int i = 0; i < 1000000; i++)
            {
                try
                {
                    throw new Exception();
                }
                catch {}
            }
            Console.WriteLine(sw.ElapsedMilliseconds);
            Console.Read();
        }
    }
}

Solution 5 - .Net

The compiler emits more IL when you wrap code inside a try/catch block; Look, for the following program :

using System;
public class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("abc");
    }
}

The compiler will emit this IL :

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       13 (0xd)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ldstr      "abc"
  IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_000b:  nop
  IL_000c:  ret
} // end of method Program::Main

While for the slightly modified version :

using System;
public class Program
{
    static void Main(string[] args)
    {
        try { Console.WriteLine("abc"); }
        catch { }
    }
}

emits more :

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       23 (0x17)
  .maxstack  1
  IL_0000:  nop
  .try
  {
    IL_0001:  nop
    IL_0002:  ldstr      "abc"
    IL_0007:  call       void [mscorlib]System.Console::WriteLine(string)
    IL_000c:  nop
    IL_000d:  nop
    IL_000e:  leave.s    IL_0015
  }  // end .try
  catch [mscorlib]System.Object 
  {
    IL_0010:  pop
    IL_0011:  nop
    IL_0012:  nop
    IL_0013:  leave.s    IL_0015
  }  // end handler
  IL_0015:  nop
  IL_0016:  ret
} // end of method Program::Main

All these NOPs and others cost.

Solution 6 - .Net

IMO this whole discussion is like saying "wow lops are expensive because I need to increment a counter... i'm not going to use them any more", or "wow creating an object takes time, i'm not going to create a ton of objects any more."

Bottom line is your adding code, presumably for a reason. If the lines of code didn't then incur some overhead, even if its 1 CPU cycle, then why would it exist? Nothing is free.

The wise thing to do, as with any line of code you add to your application, is to only put it there if you need it to do something. If catching an exception is something you need to do, then do it... just like if you need a string to store something, create a new string. By the same means, if you declare a variable that isn't ever used, you are wasting memory and CPU cycles to create it and it should be removed. same with a try/catch.

In other words, if there's code there to do something, then assume that doing something is going to consume CPU and/or memory in some way.

Solution 7 - .Net

It's not try blocks you need to worry about as much as catch blocks. And then, it's not that you want to avoid writing the blocks: it's that you want as much as possible to write code that will never actually use them.

Solution 8 - .Net

I doubt if they are particularly expensive. A lot of times, they are necessary/required.

Though I strongly recommend using them only when necessary and at the right places / level of nesting instead of rethrowing the exception at every call return.

I would imagine the main reason for the advice was to say that you shouldnt be using try-catches where if---else would be a better approach.

Solution 9 - .Net

This is not something I would ever worry about. I would rather care about the clarity and safety of a try...finally block over concerning myself with how "expensive" it is.

I personally don't use a 286, nor does anyone using .NET or Java either. Move on. Worry about writing good code that will affect your users and other developers instead of the underlying framework that is working fine for 99.999999% of the people using it.

This is probably not very helpful, and I don't mean to be scathing but just highlighting perspective.

Solution 10 - .Net

Slightly O/T, but...

There is fairly good design concept that says you should never require exception handling. This means simply that you should be able to query any object for any conditions that might throw an exception before that exception would be thrown.

Like being able to say "writable()" before "write()", stuff like that.

It's a decent idea, and if used, it makes checked exceptions in Java look kind stupid--I mean, checking for a condition and right after that, being forced to still write a try/catch for the same condition?

It's a pretty good pattern, but checked exceptions can be enforced by the compiler, these checks can't. Also not all libraries are made using this design pattern--it's just something to keep in mind when you are thinking about exceptions.

Solution 11 - .Net

Every try needs to record a lot of information, e.g. stack pointers, values of CPU register, etc. so it can unwind the stack and bring back the state it has been when passing the try block in case an exception is thrown. Not only that every try needs to record a lot of information, when an exception is thrown, a lot of values needs to be restored. So a try is very expensive and a throw/catch is very expensive, too.

That doesn't mean you shouldn't use exceptions, however, in performance critical code you should maybe not use too many tries and also not throw exceptions too often.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionEsteban ArayaView Question on Stackoverflow
Solution 1 - .NetBob KingView Answer on Stackoverflow
Solution 2 - .NetScott DormanView Answer on Stackoverflow
Solution 3 - .NetAnthonyView Answer on Stackoverflow
Solution 4 - .NetMichael PetrottaView Answer on Stackoverflow
Solution 5 - .NetAndrei RîneaView Answer on Stackoverflow
Solution 6 - .NetCodingWithSpikeView Answer on Stackoverflow
Solution 7 - .NetJoel CoehoornView Answer on Stackoverflow
Solution 8 - .NetMostlyharmlessView Answer on Stackoverflow
Solution 9 - .NetRhysCView Answer on Stackoverflow
Solution 10 - .NetBill KView Answer on Stackoverflow
Solution 11 - .NetMeckiView Answer on Stackoverflow