What Is the Real Overhead of Try/Catch in C#

What is the real overhead of try/catch in C#?

I'm not an expert in language implementations (so take this with a grain of salt), but I think one of the biggest costs is unwinding the stack and storing it for the stack trace. I suspect this happens only when the exception is thrown (but I don't know), and if so, this would be decently sized hidden cost every time an exception is thrown... so it's not like you are just jumping from one place in the code to another, there is a lot going on.

I don't think it's a problem as long as you are using exceptions for EXCEPTIONAL behavior (so not your typical, expected path through the program).

try catch for performance c#

The link I provided in the above comment shows a description of why you shouldn't ever use a try-catch when an if-statement would prevent the exception from being thrown, but in the interest of showing performance in terms of actual numbers, I wrote this quick little test program.

Stopwatch watch = new Stopwatch();

int[] testArray = new int[] { 1, 2, 3, 4, 5 };
int? test = null;

watch.Start();
for (int i = 0; i < 10000; i++)
{
try
{
testArray[(int)test] = 0;
}
catch { }
}
watch.Stop();

Console.WriteLine("try-catch result:");
Console.WriteLine(watch.Elapsed);
Console.WriteLine();

watch.Restart();
for (int i = 0; i < 10000; i++)
{
if (test != null)
testArray[(int)test] = 0;
}
watch.Stop();

Console.WriteLine("if-statement result:");
Console.WriteLine(watch.Elapsed);

The result of the program is this:

try-catch result:
00:00:32.6764911

if-statement result:
00:00:00.0001047

As you can see, the try-catch approach introduces significant overhead when an exception gets caught, taking over 30 seconds to complete 10,000 cycles on my machine. The if-statement, on the other hand, runs so fast that it is basically instantaneous. Compared to the try-catch, this is a performance improvement in the neighborhood of 3,000,000%.

(This isn't a rigorous benchmark, and there are ways to write it and run it differently to get more precise numbers, but this should give you a good idea of just how much more efficient it is to use an if-statement over a try-catch whenever possible.)

Do try/catch blocks hurt performance when exceptions are not thrown?

Check it.

static public void Main(string[] args)
{
Stopwatch w = new Stopwatch();
double d = 0;

w.Start();

for (int i = 0; i < 10000000; i++)
{
try
{
d = Math.Sin(1);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}

w.Stop();
Console.WriteLine(w.Elapsed);
w.Reset();
w.Start();

for (int i = 0; i < 10000000; i++)
{
d = Math.Sin(1);
}

w.Stop();
Console.WriteLine(w.Elapsed);
}

Output:

00:00:00.4269033  // with try/catch
00:00:00.4260383 // without.

In milliseconds:

449
416

New code:

for (int j = 0; j < 10; j++)
{
Stopwatch w = new Stopwatch();
double d = 0;
w.Start();

for (int i = 0; i < 10000000; i++)
{
try
{
d = Math.Sin(d);
}

catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}

finally
{
d = Math.Sin(d);
}
}

w.Stop();
Console.Write(" try/catch/finally: ");
Console.WriteLine(w.ElapsedMilliseconds);
w.Reset();
d = 0;
w.Start();

for (int i = 0; i < 10000000; i++)
{
d = Math.Sin(d);
d = Math.Sin(d);
}

w.Stop();
Console.Write("No try/catch/finally: ");
Console.WriteLine(w.ElapsedMilliseconds);
Console.WriteLine();
}

New results:

   try/catch/finally: 382
No try/catch/finally: 332

try/catch/finally: 375
No try/catch/finally: 332

try/catch/finally: 376
No try/catch/finally: 333

try/catch/finally: 375
No try/catch/finally: 330

try/catch/finally: 373
No try/catch/finally: 329

try/catch/finally: 373
No try/catch/finally: 330

try/catch/finally: 373
No try/catch/finally: 352

try/catch/finally: 374
No try/catch/finally: 331

try/catch/finally: 380
No try/catch/finally: 329

try/catch/finally: 374
No try/catch/finally: 334

Performance cost of a try/catch block

From MSDN site:

Finding and designing away
exception-heavy code can result in a
decent perf win. Bear in mind that
this has nothing to do with try/catch
blocks: you only incur the cost when
the actual exception is thrown. You
can use as many try/catch blocks as
you want. Using exceptions
gratuitously is where you lose
performance. For example, you should
stay away from things like using
exceptions for control flow.

Also see these related SO questions: (1) (2) (3) and (4).

Overhead of try/finally in C#?

Why not look at what you actually get?

Here is a simple chunk of code in C#:

    static void Main(string[] args)
{
int i = 0;
try
{
i = 1;
Console.WriteLine(i);
return;
}
finally
{
Console.WriteLine("finally.");
}
}

And here is the resulting IL in the debug build:

.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.maxstack 1
.locals init ([0] int32 i)
L_0000: nop
L_0001: ldc.i4.0
L_0002: stloc.0
L_0003: nop
L_0004: ldc.i4.1
L_0005: stloc.0
L_0006: ldloc.0 // here's the WriteLine of i
L_0007: call void [mscorlib]System.Console::WriteLine(int32)
L_000c: nop
L_000d: leave.s L_001d // this is the flavor of branch that triggers finally
L_000f: nop
L_0010: ldstr "finally."
L_0015: call void [mscorlib]System.Console::WriteLine(string)
L_001a: nop
L_001b: nop
L_001c: endfinally
L_001d: nop
L_001e: ret
.try L_0003 to L_000f finally handler L_000f to L_001d
}

and here's the assembly generated by the JIT when running in debug:

00000000  push        ebp 
00000001 mov ebp,esp
00000003 push edi
00000004 push esi
00000005 push ebx
00000006 sub esp,34h
00000009 mov esi,ecx
0000000b lea edi,[ebp-38h]
0000000e mov ecx,0Bh
00000013 xor eax,eax
00000015 rep stos dword ptr es:[edi]
00000017 mov ecx,esi
00000019 xor eax,eax
0000001b mov dword ptr [ebp-1Ch],eax
0000001e mov dword ptr [ebp-3Ch],ecx
00000021 cmp dword ptr ds:[00288D34h],0
00000028 je 0000002F
0000002a call 59439E21
0000002f xor edx,edx
00000031 mov dword ptr [ebp-40h],edx
00000034 nop
int i = 0;
00000035 xor edx,edx
00000037 mov dword ptr [ebp-40h],edx
try
{
0000003a nop
i = 1;
0000003b mov dword ptr [ebp-40h],1
Console.WriteLine(i);
00000042 mov ecx,dword ptr [ebp-40h]
00000045 call 58DB2EA0
0000004a nop
return;
0000004b nop
0000004c mov dword ptr [ebp-20h],0
00000053 mov dword ptr [ebp-1Ch],0FCh
0000005a push 4E1584h
0000005f jmp 00000061
}
finally
{
00000061 nop
Console.WriteLine("finally.");
00000062 mov ecx,dword ptr ds:[036E2088h]
00000068 call 58DB2DB4
0000006d nop
}
0000006e nop
0000006f pop eax
00000070 jmp eax
00000072 nop
}
00000073 nop
00000074 lea esp,[ebp-0Ch]
00000077 pop ebx
00000078 pop esi
00000079 pop edi
0000007a pop ebp
0000007b ret
0000007c mov dword ptr [ebp-1Ch],0
00000083 jmp 00000072

Now, if I comment out the try and finally and the return, I get nearly identical assembly from the JIT. The differences you'll see are a jump into the finally block and some code to figure out where to go after the finally is executed. So you're talking about TINY differences. In release, the jump into the finally will get optimized out - braces are nop instructions, so this would become a jump to the next instruction, which is also a nop - that's an easy peephole optimization. The pop eax and then jmp eax is similarly cheap.

    {
00000000 push ebp
00000001 mov ebp,esp
00000003 push edi
00000004 push esi
00000005 push ebx
00000006 sub esp,34h
00000009 mov esi,ecx
0000000b lea edi,[ebp-38h]
0000000e mov ecx,0Bh
00000013 xor eax,eax
00000015 rep stos dword ptr es:[edi]
00000017 mov ecx,esi
00000019 xor eax,eax
0000001b mov dword ptr [ebp-1Ch],eax
0000001e mov dword ptr [ebp-3Ch],ecx
00000021 cmp dword ptr ds:[00198D34h],0
00000028 je 0000002F
0000002a call 59549E21
0000002f xor edx,edx
00000031 mov dword ptr [ebp-40h],edx
00000034 nop
int i = 0;
00000035 xor edx,edx
00000037 mov dword ptr [ebp-40h],edx
//try
//{
i = 1;
0000003a mov dword ptr [ebp-40h],1
Console.WriteLine(i);
00000041 mov ecx,dword ptr [ebp-40h]
00000044 call 58EC2EA0
00000049 nop
// return;
//}
//finally
//{
Console.WriteLine("finally.");
0000004a mov ecx,dword ptr ds:[034C2088h]
00000050 call 58EC2DB4
00000055 nop
//}
}
00000056 nop
00000057 lea esp,[ebp-0Ch]
0000005a pop ebx
0000005b pop esi
0000005c pop edi
0000005d pop ebp
0000005e ret

So you're talking very, very tiny costs for try/finally. There are very few problem domains where this matters. If you're doing something like memcpy and put a try/finally around each byte being copied and then proceed to copy hundreds of MB of data, I could see that being an issue, but in most usage? Negligible.

try catch performance

The JIT doesn't perform optimization on 'protected' / 'try' blocks and I guess depending on the code you write in try/catch blocks, this will affect your performance.

Try..Catch blocks always expensive?

In general, in today's implementations, entering a try block is not expensive at all (this was not always true). However, throwing and handling an exception is usually a relatively expensive operation. So, exceptions should normally be used for exceptional events, not normal flow control.

Performance is only one factor to consider, though, especially in the modern world. If (for instance) you're doing something once in response to a user action, it probably doesn't matter from a performance standpoint whether you use an exception even when you could have done a proactive check instead, provided the exception happens quickly enough the user isn't jolted.¹ But if you're doing something in a tight loop that's going to run hundreds of thousands of times, or you're writing a web application that may need to handle a huge load, you'd probably want to avoid using an exception for a normal case.


¹ More than a decade ago I was responsible for enhancements to a .Net 1.1 "no touch deployment" application in which the first exception thrown took fully three seconds. This was a sufficient problem in one use case involving opening a file the user had asked for which might reasonably not be there that I had to add a check for file existence prior to trying to open the file, which is normally poor programming practice (just try to open the file and handle the exception if that fails), purely because the user experience waiting for that exception to get built was so poor. But that's probably not the world we live in now.

How often should I use try and catch in C#?

The only down side is when an exception is actually thrown. There is no overhead for wrapping the code, except for when exceptions occur.

Also, you don't want to use try/catch for control flow. Consider this (bad code):

try {

FileStream fs = File.Open("somefile.txt", FileMode.Open);

} catch (Exception ex) {
MessageBox.Show("The file does not exist. Please select another file");
}

You'll get more performance from some thing like File.Exists. such as:

if(!File.Exists("somefile.txt"))
MessageBox.Show("The file does not exist.")

EDIT:
found the MSDN direct quote:

Finding and designing away
exception-heavy code can result in a
decent perf win. Bear in mind that
this has nothing to do with try/catch
blocks: you only incur the cost when
the actual exception is thrown. You
can use as many try/catch blocks as
you want. Using exceptions
gratuitously is where you lose
performance. For example, you should
stay away from things like using
exceptions for control flow.

Try-Catch vs If performance in C#

Exceptions are not made to control the flow of your code. They are made to treat "exceptional" circumstances, e.g. connection issues or invalid file formats.

If you want to control your code flow, you should use conditional statements like if, else and switch.

The performance of exceptions is generally bad compared to some simple if-statement, but there are also situations when exception-handling might be even faster than checking data for validity manually, especially if you don't know how to do it fast.
There might also be plenty of situations where you "know" an exception could be raised, but you simply trust the data - e.g. checking your own settings file for valid xml format.

Most of the time, you want to use Exceptions, to have error information later, e.g. line number of the error in the xml file and to recover your application in some way (e.g. reconnect to a socket).

You can not give a general statement about the performance of exceptions, but when you can avoid them, you should.
They are made for exceptions as their name already tells.

A small example where you can potentially avoid exceptions:

try
{
LoginUser("Fooooo", "Bar");
} catch(InvalidPasswordException e) {
MessageBox.Show(e.Message);
}

private static void LoginUser(string pUsername, string pPassword)
{
if (pUsername != "Foo" || pPassword != "Bar")
throw new InvalidPasswordException("Invalid username and/or password");

GrantAccess(pUsername);
}

Instead of throwing the exception you could also just return a boolean:

if (!LoginUser("Fooooo", "Bar"))
{
MessageBox.Show("Invalid username and/or password");
}

private static bool LoginUser(string pUsername, string pPassword)
{
if (pUsername != "Foo" || pPassword != "Bar")
return false;

GrantAccess(pUsername);
return true;
}

Performance-Test: 10000 attempts with false credentials:

throwing Exception (without displaying the messagebox): 181990454 ticks

returning boolean: 644 ticks

And we are only 1 layer into the application, so there is not much stacktrace to be generated. I guess you can see and especially feel the difference.

Under C# how much of a performance hit is a try, throw and catch block

Throw (rather than catch) is expensive.

Don't put a catch block in unless you are going to do something useful (i.e. convert to a more useful exception, handle the error).

Just rethrowing the exception (throw statement without argument) or, even worse, throw the same object as just caught is definitely the wrong thing.

EDIT: To avoid ambiguity:

Rethrow:

catch (SomeException) {
throw;
}

Create exception from previous exception object, where all the runtime provided state (notably stack trace) is overwritten:

catch (SomeException e) {
throw e;
}

The latter case is a pointless way to throw away information about the exception. and without anything preceding the throw in the catch block is doubly pointless. It can be worse:

catch (SomeException e) {
throw new SomeException(e.Message);
}

which loses almost all the useful state information e contained (including what was originally thrown.)



Related Topics



Leave a reply



Submit