I saw
Jacob Cynamon speak at the local .NET user's group last night. He presents well and has a cool name. His topic was general performace tuning for the .net framework.
Having gone through an "oh no perforance sucks" experience on a large ASP.NET project and an almost as large compact framework project already this year, this topic was of some interest to me; I wanted to see if I'd missed
anything major.
The presentation was good, but it did look like I've hit the major points in my own optimization efforts. I wanted to add my own points to two of Jacob's: the cost of boxing and the cost
of throwing exceptions.
Everyone talks about how expensive
boxing is as if it's like downloading a 5 meg file over a 14400baud modem. Until last night I had not thought about exactly
why boxing is so expensive or how expensive it is compared to other operations. Jacob's initial example showed value type assignment, compared to value type to object and object to
value type. The boxing operation took about 13 times as long as assigning a value type. The first impression might be "See, boxing is the devil, we told you so". What could make it so
expensive an operation? If I were implementing it I would create a container object to hold the value type and return it when asked. The cost would just be the creation of an object on the
heap and maybe a tiny bit of relfection.
After the presentation was over I asked if he could throw
a fourth comparison in there:
object o = new object();. Sure enough, just calling "new()" took 99% as long as the boxing operation. What's my point?
Yes, boxing is expensive compared to
just using value types. Run CLR profiler once and see how many objects are created and garbage collected during a mundane operation we take for granted in .NET, like calling a web service. Boxing will
be pretty low on my list of things to look for next time I need to squeeze performance out of an application.
The next item I wanted to add to was throwing exceptions. I read a statistic on MSDN somewhere (I can't find the link now) that claimed throwing an exception slowed down the executing thread
by a factor of six, or something like that. This makes some sense, in terms of the op codes that would need to be executed to suddenly break execution a lot of things
would need to happen: doing a "goto" and running
Dispose methods for
using and
try/finally blocks can't be cheap.
My thought regarding exceptions was similar to my thought on boxing. You should only use exceptions for exceptional situations, not to control program flow. This is not a new tip, I read it first in
one of Bjarne Stroustrup's
books on the language he invented.
Many developers
may not be aware of how many exceptions the .NET class libraries are throwing and subsequently swallowing. You'll never see these exceptions unless you run your app in the debugger, and set all CLR
exceptions to break into the debugger whether or not they are handled. You might be surprised how many times security violation exceptions are thrown while trying to read resource files, or to know
that VB methods like CanParse or IsDate function by just trying to Parse and catching the
FormatException if the operation fails. Depending on what functions your app is calling
you may be suffering from hundreds or thousands of swallowed exceptions, especially at the time your app starts up.
Matt Terski gave another good example in that
every time you call Response.Redirect("foo") in ASP.NET a ThreadAbortedException is thrown. Check those First Chance excpetions!