![]() |
General Programming »
Exception Handling »
General
Intermediate
Performance implications of Exceptions in .NETBy Vagif AbilovPresentation and analysis of performance costs when throwing exceptions in .NET. |
C#.NET 1.1, .NET 2.0, Win2K, WinXPVS.NET2003, VS2005, Dev
|
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||
One of the important changes to programming style that .NET brought to developers was the use of exceptions as the primary method of error handling. This was not a revolutionary approach, since exceptions has 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 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.
To collect performance measurements I have written a small .NET Windows Forms application. Using this application it is possible to specify a job type, how to throw (or not throw) 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:
In addition the application defines five modes of exceptions:
try-catch block, but no exception is thrown.
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 1 second interval.
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 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.
Now let�s look at how much the use of an exception costs. The results are shown in a 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 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 rethrowing an original one, so you should not be afraid of doing this just for performance reasons.
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 call stack. 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 the 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.
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 big impact on performance, at least not big enough to make 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 architecture without noticeable performance impact.
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 9 Aug 2005 Editor: Rinish Biju |
Copyright 2005 by Vagif Abilov Everything else Copyright © CodeProject, 1999-2009 Web21 | Advertise on the Code Project |