You have a project consisting of some very complex code that is a performance bottleneck for the entire application. You have been assigned to increase performance, but you do not know where to start looking.
A great way to start looking for performance problems is to use a profiling tool to see whether boxing is actually causing you any kind of problem in the first place. A profiler will show you exactly what allocations are occurring and in what volume. There are several profilers on the market; some are free and others are not.
If you have already established through profiling that boxing is
definitely causing a problem but you are still having trouble working
out where it’s occurring, then you can use the
Ildasm
disassembler tool that is packaged with VS.NET. With Ildasm you can
convert an entire project to its equivalent IL code and then dump the
IL to a text file. To do this, Ildasm has several command-line
switches, one of which is the /output
switch. This
switch is used as follows:
ildasm Proj1.dll /output:Proj1.il
This command will disassemble the file Proj1.dll
and then write the disassembled IL to the file
Proj1.il
.
A second useful command-line switch is /source
.
This switch shows the original code (C#, VB.NET, etc.) in which this
DLL was written, as well as the IL that was compiled from each of
these source lines. Note that the DLL must be built with debugging
enabled. This switch is used as follows:
ildasm Proj1.dll /output:Proj1.il /source
We prefer the second method of invoking Ildasm, since the original source is included, preventing you from getting lost in all of the IL code.
After running Ildasm from the command line, open the resulting IL
code file into VS.NET or your favorite editor. Inside the editor, do
a text search for the words box and
unbox
. This will find all occurrences of boxing
and unboxing operations.
Using this information, you have pinpointed the problem areas. Now, you can turn your attention to them to see if there is any way to prevent or minimize the boxing/unboxing operations.
When a boxing or unboxing operation occurs in code, whether it was
implicit or explicit, the IL generated includes the
box
or unbox
command. For
example, the following C# code:
int valType = 1; object boxedValType = valType; valType = (int)boxedValType;
compiles to the following IL code:
//000883: int valType = 1; IL_0000: ldc.i4.1 IL_0001: stloc.0 //000884: object boxedValType = valType; IL_0002: ldloc.0 IL_0003: box [mscorlib]System.Int32 IL_0008: stloc.1 //000898: int valType = (int) boxedValType; IL_0061: ldloc.1 IL_0062: unbox [mscorlib]System.Int32 IL_0067: ldind.i4
Notice the box
and unbox
commands in the previous IL code. IL makes it very apparent when a
boxing or unboxing operation occurs. We can use this to our advantage
to find and hopefully prevent a boxing operation from occurring.
The following can help prevent or eliminate boxing:
Use classes instead of structures. This usually involves simply
changing the struct
keyword to
class
in the structure definition. This very
simple and quick change can dramatically improve performance.
Do not implement explicit interface members on structures. As the discussion shows, this causes the structure to be boxed before the call to an interface member is made through the interface. This reflects the fact that explicit implementation of a method on an interface is only accessible from the interface type. This means that the structure must be cast to that interface type before the explicitly declared methods of that interface type can be used. An interface is a reference type and therefore causes the structure to be boxed when an explicit interface method is accessed on that structure.
See the “Boxing Conversion” and “Unboxing Conversion” topics in the MSDN documentation.
Below is a list of some available profiling tools:
Allocation Profiler (free), which can be obtained in the UserSamples section of the web site http://www.gotdotnet.com/community/usersamples/.
DevPartner Profiler Community Edition (free), which can be obtained at http://www.compuware.com/products/devpartner/profiler/.
DevPartner Studio Professional Edition (purchase), which can be purchased at http://www.compuware.com/products/devpartner/studio/. This package contains the code profiler tool as well as many other tools that work with .NET and other .NET code. This package also contains a memory analysis tool that can aid in debugging performance problems.