Avoid Boxing When Using String.Format with Value Types

9. August 2006 03:04

If you have worked with .NET much at all, then you have undoubtedly used String.Format.  It is one of those essential functions that just makes development a lot simpler.  However, I have found that a lot of people don't realize they are introducing a boxing operation when passing value types (byte, int, double, etc) as parameters to String.Format.

If you look closely at the signature of the String.Format method, you will notice that the arguments passed for formatting are of type object.  When a value type is passed as one of the object parameters, it requires a boxing operation.  In case you didn't know, boxing is a mechanism to convert a value type to a reference type.  Value types are stored on the stack, but reference types are allocated on the managed heap.  In order for a value type to be used as an object, the runtime must allocate memory on the heap.  The value type is then copied from the stack to the heap.  This results in a reference to the value on the heap (just like any other reference type).  There is also an operation known as unboxing, which is simply the opposite (copying from the heap to the stack).

While boxing can be very convenient when you want to use a value type as a reference type, it can introduce performance degradation.  In some situations, the performance variation may be negligible.  However, if you aren't judicious with the manner in which it is used, then you may experience unnecessarily poor performance.

Here is a seemingly innocent method that uses String.Format:

public void ProcessOrder(int orderID)
{
    string message = String.Format("Started Processing Order {0}.", orderID);

    // Log Message
    // Process the Order
}

However, examining the generated IL reveals that the integer causes a boxing operation:

.method public hidebysig instance void  ProcessOrder(int32 orderID) cil managed
{
  // Code size       19 (0x13)
  .maxstack  2
  .locals init ([0] string message)
  IL_0000:  nop
  IL_0001:  ldstr      "Started Processing Order {0}."
  IL_0006:  ldarg.1
  IL_0007:  box        [mscorlib]System.Int32
  IL_000c:  call       string [mscorlib]System.String::Format(string,
                                                              object)
  IL_0011:  stloc.0
  IL_0012:  ret
}

Fortunately, it is very easy to avoid the boxing operation by using the ToString method on the integer parameter.  Here is our method with the very simple addition of the ToString method:

public void ProcessOrder(int orderID)
{
    string message = String.Format("Started Processing Order {0}.", orderID.ToString());

    // Log Message
    // Process the Order
}

After reviewing the updated IL, you can see that the boxing operation is avoided since a string (a reference type) is being passed rather than an integer (a value type). 

.method public hidebysig instance void  ProcessOrder(int32 orderID) cil managed
{
  // Code size       20 (0x14)
  .maxstack  2
  .locals init ([0] string message)
  IL_0000:  nop
  IL_0001:  ldstr      "Started Processing Order {0}."
  IL_0006:  ldarga.s   orderID
  IL_0008:  call       instance string [mscorlib]System.Int32::ToString()
  IL_000d:  call       string [mscorlib]System.String::Format(string,
                                                              object)
  IL_0012:  stloc.0
  IL_0013:  ret
}

The instantiation of a string is more efficient than the boxing operation.  It is directly created on the heap as opposed to copying the value from the stack (boxing of the integer). 

It should be noted that this also applies to similar method overloads such as Console.WriteLine.

While this particular example may be a minimal performance difference, it is still important to understand the consequences of boxing and be able to recognize situations when it occurs.

Comments

11/7/2013 9:12:42 AM #

pingback

Pingback from askprogramming.com

Boxing and Unboxing in String.Format(…) … is the following rationalized? | Ask Programming & Technology

askprogramming.com |

Comments are closed

About Me

I'm a passionate software developer and advocate of the Microsoft .NET platform.  In my opinion, software development is a craft that necessitates a conscious effort to continually improve your skills rather than falling into the trap of complacency.  I was also awarded as a Microsoft MVP in Connected Systems in 2008, 2009, and 2010.


Can’t code withoutThe best C# & VB.NET refactoring plugin for Visual Studio
Follow jeff_barnes on Twitter

View Jeff Barnes's profile on LinkedIn

 

Shared Items

Disclaimer

Anything you read or see on this site is solely based on my own thoughts.  The material on this site does not necessarily reflect the views of my employer or anyone else.  In other words, I don't speak for anyone other than myself.  So, don't assume I am the official spokesperson for anyone.