Click here to Skip to main content
Click here to Skip to main content

Performance implications of Exceptions in .NET

, 9 Aug 2005 CPOL
Rate this:
Please Sign up or sign in to vote.
Presentation and analysis of performance costs when throwing exceptions in .NET.

Introduction

One of the important changes to programming style that .NET brought to developers is the use of exceptions as the primary method of error handling. This is not a revolutionary approach since exceptions have been actively used in various programming languages, but for a generation of programmers trained on traditional Windows and COM APIs, it did require change of their habits. No more HRESULT analysis, no more struggling with E_ACCESSDENIED, no more traversing of records obtained through the IErrorInfo interface. Just throw, try, catch, and finally.

Since the initial release of .NET, there’s been a discussion on whether Microsoft has gone too far with abandoning error codes. In this article, I will not go into arguments on that matter. Larry Osterman from Microsoft in his blog articles "Exceptions as repackaged error codes" and "Error Code Paradigms" covers some aspects of this discussion. An excellent set of guidelines was compiled by Krzysztof Cwalina. Of course, Microsoft also published various recommendations on exceptions' best practices, including "Error Raising and Handling Guidelines". So I will not try to answer the question "to throw or not to throw?". Honestly, if I knew the definitive answer of such a question, I would not have spent time to write programs just to study exceptions behavior. But I don’t. So I felt I had to thoroughly investigate various aspects of using exceptions. And one of the most important aspects is their performance. Exceptions cost. Throwing them without understanding how much they cost may have a negative impact on your application. In this article, I will present performance results measured using different scenarios, including throwing exceptions from methods of different complexity, within a single AppDomain and across domains.

Benchmark application

To collect performance measurements, I have written a small .NET Windows Forms application. Using this application, it is possible to specify the job type, how to throw (or not throw) an exception, and select a time interval while the selected job is executed. When the time expires, the application shows the job execution count. Its main screen is shown in figure 1.

Figure 1. Exception performance benchmark application.

There are five job types that can be executed:

  • Empty - As it’s easy to guess, an empty method.
  • String processing - A string "The quick brown fox jumps over the lazy dog" is split into words and each word is then uppercased.
  • File access - The application reads the contents of every file in the current directory.
  • Database - A SQL statement "SELECT * FROM Products" is executed using SQL Server ADO.NET provider and Northwind database.
  • Complex - A combination of string (8 times), file (4 times), and database (2 times) operations. This is a simulation of a simple business logic operation, although a very light one, since both file and database operations are read-only.

In addition, the application defines five modes of exceptions:

  • No exception - Plain job execution.
  • Catch without exception - Method is executed inside a try-catch block, but no exception is thrown.
  • Throw - A single exception is thrown and caught after the job is executed.
  • Rethrow original - An exception is thrown, caught, and re-thrown.
  • Rethrow new - An exception is thrown, caught, and then a new exception is thrown with the original one set as an inner exception.

Since exceptions drag quite a lot of information, in case the method is executed across AppDomains and results in exception, it incurs considerable extra costs related to its serialization. To measure such costs, I have added the possibility to execute selected jobs in a separate AppDomain.

Below I present the results of application execution on my Dell Latitude D800 with Pentium M 1.70 GHz. Every test was executed using a 1 second interval.

The perfect world: no exceptions

To begin with our benchmarking, we need to gather reference data: how fast is the code when no exceptions are thrown? Table 1 shows this information:

Mode/operation Empty String File Database Complex
No exception 17,748,206 267,300 2,461 877 239
Catch without exception 15,415,757 261,456 2,476 871 236
Table 1. No exceptions thrown (executions per second).

It is too early to make conclusions at this stage, but two things can be observed. First, there is no cost in a try-catch block (might sound obvious but I’ve heard arguments that low level code should avoid try-catch blocks for performance reasons). Second, with a difference of 100,000 times between empty and complex operations, it does not make much sense to talk about absolute costs of using exceptions. They must be analyzed in the context of operations.

The real world: exceptions added

Now let’s look at how much the use of an exception costs. The results are shown in table 2:

Mode/operation Empty String File Database Complex
Throw 103,456 68,952 2,236 864 236
Rethrow original 53,481 41,889 2,324 852 230
Rethrow new 55,712 43,140 2,269 847 232
Table 2. Exceptions thrown (executions per second).

Here we can see that exceptions do not present a significant performance threat for operations that are more complex than simple calculation algorithms. Only primitive string processing was affected by raised exceptions. As soon as the method involves accessing files or databases (and majority of them do), the cost of exceptions become really marginal.

Another observation is that wrapping an exception in a new one does not really affect the performance compared to re-throwing an original one, so you should not be afraid of doing this just for performance reasons.

The heavy world: sending exceptions across application domains

If you recognize exceptions as the sole method of propagating error information and replace them with numerical traditional error codes, you should be aware of the associated costs of cross-domain exception marshalling. Every exception is a large packet of information that includes even a callstack. When being sent across threads or application domains, this packet is serialized and de-serialized, and of course this comes at a price. Table 3 shows these costs:

Mode/operation Empty String File Database Complex
No exception 44,437 36,101 1,458 749 175
Throw 3,073 2,942 930 574 160
Rethrow original 2,950 2,881 929 588 158
Rethrow new 2,882 2,875 938 577 158
Table 3. Exceptions thrown across domains (executions per second).

As you can see, application domains are performance killers by themselves. An empty method is executed with a speed that is more than 400 times slower than execution within the same domain! Think twice before splitting your components between different domains. However, sometimes this is an only option, and in such cases, exceptions add even more to the performance costs. For simple computational tasks, exception handling will use more than 90% of the processing time. Even for file access operations, cross-domain exception marshalling slows down the execution to almost half the speed. But more complex business logic operations can still afford to throw exceptions even in multiple domain environments.

Conclusion

Exception handling is much more than its performance aspects. Here, I have not touched such topics as whether exceptions should be thrown only in abnormal situations or they should cover all unsuccessful operational states. Perhaps the only conclusion I can draw from the presented results is that for everything but simple computational algorithms, exceptions do not have a big impact on performance, at least not big enough to make a design decision regarding exceptions based mostly on performance reasons. You should carefully apply the guidelines presented in the referenced articles and in case performance is of high concern, implement additional methods that will help avoid unnecessary raising of exceptions (Tester-Doer and Try-Parse patterns in Krzysztof Cwalina’s article). But in general, exceptions will fit in most architectures without a noticeable performance impact.

References

  1. Exception Throwing Guidelines by Krzysztof Cwalina
  2. Exceptions as repackaged error codes by Larry Osterman
  3. Error Code Paradigms by Larry Osterman
  4. Error Raising and Handling Guidelines by Microsoft

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Vagif Abilov
Architect Miles AS
Norway Norway
Vagif Abilov is a Russian/Norwegian software developer and architect working for Miles. He has more than twenty years of programming experience that includes various programming languages, currently using mostly C# and F#.
 
Vagif writes articles and speaks at user group sessions and conferences. He is a contributor and maintainer of several open source projects, including Simple.Data OData adapter, Simple.OData.Client and MongOData.
Follow on   Twitter

Comments and Discussions

 
Questionuseful info PinmemberCIDev21-Dec-11 7:58 
GeneralMy vote of 1 PinmemberJoe Woodbury12-Jan-09 8:24 
GeneralRe: My vote of 1 PinmemberPIEBALDconsult9-May-09 10:03 
GeneralRe: My vote of 1 PinmemberVagif Abilov9-May-09 12:36 
"It examines exceptions in the context of relatively heavy database operations"
 
Not only in that context, but yes, including the context of database operations. And this what more than 90% of programmers face every day. If you take .NET you can see that CLR discourages use of deterministic memory management: you never know when the memory allocated to a released object is really realesed. 10 years ago this was a shocking news for many. Today who insists on explicit memory release? The same goes with exceptions. What will you suggest instead? Relying on HRESULTs? Been there, done that. Or do you mean that for majority of us exception performance means a lot? Then please present your results. I presented mine.
 
Вагиф Абилов
MCP (Visual C++)
Oslo, Norway

 
If you're in a war, instead of throwing a hand grenade at the enemy, throw one of those small pumpkins. Maybe it'll make everyone think how stupid war is, and while they are thinking, you can throw a real grenade at them.
Jack Handey.

GeneralI dont care what anybody says.... PinmemberNick Z.16-Aug-05 9:16 
GeneralRe: I dont care what anybody says.... PinmemberVagif Abilov19-Aug-05 0:59 
GeneralRe: I dont care what anybody says.... PinmemberZoltan Balazs7-Mar-07 7:50 
QuestionTo throw or not to throw...? Pinmemberptmcomp15-Aug-05 9:42 
AnswerRe: To throw or not to throw...? PinmemberVagif Abilov19-Aug-05 0:59 
QuestionPoint? PinmemberPeter Ritchie15-Aug-05 6:55 
AnswerRe: Point? Pinsusselmar_bartowitsch16-Aug-05 0:21 
GeneralRe: Point? PinmemberPeter Ritchie16-Aug-05 4:21 
GeneralRe: Point? PinmemberPortatofe2-Oct-08 7:00 
AnswerRe: Point? PinmemberVagif Abilov19-Aug-05 0:57 
QuestionAre exception a good thing? Pinmemberediazc11-Aug-05 18:55 
QuestionAre you all insane? PinmemberKingJinx10-Aug-05 17:00 
AnswerRe: Are you all insane? PinmemberVagif Abilov10-Aug-05 21:31 
GeneralGreat article -- and TryParse in .NET 2.0 Pinmemberwumpus110-Aug-05 13:50 
GeneralRe: Great article -- and TryParse in .NET 2.0 PinmemberVagif Abilov10-Aug-05 21:21 
GeneralGood and informative work PinmemberSuper Lloyd10-Aug-05 3:32 
GeneralRe: Good and informative work PinmemberVagif Abilov10-Aug-05 4:35 
GeneralExcellent Reference PinmemberMatt Gerrans9-Aug-05 20:47 
GeneralRe: Excellent Reference PinmemberVagif Abilov9-Aug-05 21:16 
GeneralException...ally Pinmemberian mariano9-Aug-05 16:31 
GeneralRe: Exception...ally PinmemberVagif Abilov9-Aug-05 20:11 
GeneralRe: Exception...ally Pinmemberian mariano10-Aug-05 3:47 
GeneralRe: Exception...ally PinmemberVagif Abilov10-Aug-05 4:42 
GeneralRe: Exception...ally Pinmemberian mariano10-Aug-05 4:51 
GeneralVery informative... PinmemberDrew Stainton9-Aug-05 14:47 
GeneralRe: Very informative... PinmemberVagif Abilov9-Aug-05 20:11 
GeneralRe: Very informative... Pinmembercomputerguru9238210-Aug-05 14:35 
GeneralThank you Pinmemberreinux9-Aug-05 14:47 
GeneralRe: Thank you PinmemberLivid9-Aug-05 15:18 
GeneralRe: Thank you PinmemberVagif Abilov9-Aug-05 20:14 
GeneralRe: Thank you Pinmemberreinux9-Aug-05 20:27 
GeneralRe: Thank you PinmemberVagif Abilov9-Aug-05 21:15 
GeneralRe: Thank you Pinmemberzcaccau15-Aug-05 23:10 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.141223.1 | Last Updated 9 Aug 2005
Article Copyright 2005 by Vagif Abilov
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid