Recipe3.32.Determining Where Boxing and Unboxing Occur


Recipe 3.32. Determining Where Boxing and Unboxing Occur

problem

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.

Solution

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.

Discussion

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. You can use this to your advantage to find and hopefully prevent a boxing operation from occurring.

The following can help prevent or eliminate boxing:

  1. Use classes instead of structures. This usually involves simply changing the struct keyword to class in the structure definition. This change can dramatically improve performance. However, this change should be done in a very careful manner, as it can change the operation of the application.

  2. If you are storing value types in a collection, switch to using a generic collection. The generic collection can be instantiated for the specific value type that you will be storing in it. This allows you to create a collection that is strongly typed for that specific value type. Not only will using a generic collection alleviate the boxing/unboxing issue, but it will also speed things up since there are fewer casts to perform when adding, removing, and looking up values in this collection.

  3. Take care when implementing 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 accessible only 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. However, in some cases this isn't true. For example, the using statement issues an IL instruction to prevent boxing when calling the Dispose methodassuming that an implicit interface implementation is used.

Note that changes to a value type that exists in both boxed and unboxed form occur independently of one another.


See Also

See the "Boxing Conversion" and "Unboxing Conversion" topics in the MSDN documentation.

Here 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.



C# Cookbook
Secure Programming Cookbook for C and C++: Recipes for Cryptography, Authentication, Input Validation & More
ISBN: 0596003943
EAN: 2147483647
Year: 2004
Pages: 424

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net