Click here to monitor SSC

Donahue, Crash Scene Investigator

Red Gate Support Engineer

Exceptionally expensive

Published Wednesday, March 26, 2008 1:09 PM

Many years ago, when switching from programming in plain old C to the managed environment of .NET Framework, I had discovered exceptions.  The idea was not completely new to me because I'd already seen try/catch blocks in JavaScript and I liked that method of error handling a lot, especially when compared to the ON ERROR GOTO handling that VBScript uses, which is why I prefer using JScript whenever I can, although sometimes in the scripting environment you begrudgingly have to use VBS.

.NET had significantly enhanced the try/catch block by allowing the programmer to extend the exceptions by adding their own properties and methods to them. In addition, the exceptions can be typed, so if you are interested in one type of exception, say a file can't be opened, but not in another type of exception, for instance an out-of-memory condition, you can have that sort of granularity.

So I thought, great!, I will use exceptions everywhere. I will use them all over the place, not only to handle catastrophic and unusual errors, but also anywhere an object could not be created or a value exceeded a certain threshold or any one of 1001 completely common situations where something happened that needed some conditional branching to happen. This, as I found out, could have some particularly nasty performance implications!

Here is a simple example to demonstrate just how much slower throwing exceptions can make your .NET Program:

using System;
using System.Collections.Generic;
using System.Collections;
using System.Text;
namespace ExceptionTest
{
class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 1000000; i++)
{
HandleViaException();
HandleViaCondition();
}
}
static void HandleViaException()
{
string s = null;
try{
string ss = s.Substring(0, 2);
}
catch (System.NullReferenceException)
{
}
}
static void HandleViaCondition()
{
string s = null;
if (s != null)
{
string ss = s.Substring(0, 2);
}
}
}

In the HandleViaException method, I attempt to execute a method on a string object set to a null value, which will cause a NullReferenceException and make the exception handling code run. In the HandleViaCondition method, I simply check the value of the string, and if it is null, I do not run the Substring method on the string. Although these methods perform the same function, there should be a noticable performance difference when the methods are both run a million times. I had tested this using the ANTS Profiler code profiling tool with the following results:

HandleViaCondition -- Hit Count: 1000000 Total Time: 0.571 seconds
HandleViaException -- HitCount: 1000000 Total Time: 50.4 seconds

Using Exceptions to trap a null condition is roughly a hundred times slower than simply checking to see if the string is null. I knew that using exceptions would incur a performance penalty but mama mia that is slow! I've taken a program that should return in less than a second and turned it into an excuse to hang out at the water cooler and gossip for awhile.

Could I make this any worse? Oh, yes I can, by attaching a debugger (cdb.exe) to the program as well!

HandleViaCondition -- Hit Count: 1000000 Total Time: 0.554 seconds
HandleViaException -- HitCount: 1000000 Total Time: 54.3 seconds

Well, that's not too much worse, but then again, cdb is pretty lightweight. Let's attach to it using Visual Studio 2005's debugger:

HandleViaCondition -- Hit Count: 1000000 Total Time: 0.678 seconds
HandleViaException -- HitCount: 1000000 Total Time: 1936 seconds

See, now I have a convenient excuse to go down to the cantine and get a donut. Mmmmmm, donuts.

The Visual Studio debugger is particularly invasive when it encounters an exception in the code that you're debugging. You expect a debugger to pause your code when an exception is encountered, grab information about the stack and heap, and allow your code to continue on. With CDB.exe, the overhead is pretty minimal, but Visual Studio 2005 seems to pause my running code for much longer.

The end result is that if this code was part of a real-world application, I would probably spend all day trying to debug it, and I frankly have better things to do, like eat bacon sandwiches. On toast. With some of that nice Brown Sauce they have over here.

From now on, I use exceptions in my code very sparingly, and try to avoid using them in code loops altogether because the cumulative effect of wasting a few milliseconds in a tight code loop can turn an application into sludge if you're not careful!

 

by Brian Donahue
Attachment(s): ExceptionTest.Png

Comments

 

http://blogs.red-gate.com/donahue_crash_scene_investigator/archive/2008/02/15/exceptionally-expensive.aspx said:

Originally postec on 26 March 2008 08:54 by http://blogs.red-gate.com/donahue_crash_scene_investigator/archive/2008/02/15/exceptionally-expensive.aspx
Pingback from  blogs.red-gate.com/.../exceptionally-expensive.aspx
March 26, 2008 10:58 AM
You need to sign in to comment on this blog
<March 2008>
SuMoTuWeThFrSa
2425262728291
2345678
9101112131415
16171819202122
23242526272829
303112345
Migrating from OCS 2007 R2 to Lync: Part 4
 Having migrated the rest of our users and legacy resources across, and start getting ready to... Read more...

Automated Script-generation with Powershell and SMO
 In the first of a series of articles on automating the process of building, modifying and copying SQL... Read more...

Seth Godin: Big in the IT Business
 Seth Godin has transformed our understanding of marketing in IT. He invented the concept of 'permission... Read more...

Using SQL Test Database Unit Testing with TeamCity Continuous Integration
 With database applications, the process of test and integration can be frustratingly slow because so... Read more...

Converting String Data to XML and XML to String Data
 We all appreciate that, in general, XML documents or fragments are held in strings as text markup. In... Read more...