Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.NET boxing / unboxing vs casting performance

I'm trying to understand which of two solutions are preferred from a performance perspective. For example, I have two pieces of code:

1) Boxing / Unboxing

int val = 5;
Session["key"] = val; 
int val2 = (int)Session["key"];

2) Casting (IntObj has int Value property to store int)

IntObj val = new IntObj(5);  
Session["key"] = val;
int val2 = ((IntObj )Session["key"]).Value;

What is the memory management difference between these examples? Is there a faster way to perform such operations?

NOTE: Session is just for example, it can be any Dictionary<string, object>

like image 843
Alex Dn Avatar asked Sep 06 '12 07:09

Alex Dn


People also ask

Which is faster boxing or unboxing?

Which is faster boxing or unboxing? If I look up what unboxing and boxing does you see that the difference is that boxing allocates memory on the heap and unboxing moves a value-type variable to the stack. Accesing the stack is faster than the heap and therefore unboxing is in your case faster.

How performance is affected due to boxing and unboxing?

During process of boxing and unboxing, it may be possible that the performance of conversion is being affected due the large number of items stored in a collection. I've done a bit of research over this and here is my conclusion. As a general conclusion, we can say that an object is equivalent to a 'void *' of c++.

What are the disadvantages of boxing unboxing?

Another disadvantage of using boxing is that the same object appears at two different places in memory which can have contradictory state. int a=10; object b=a; Unboxing - unboxing is a process of converting an instance of object type or interface back to value type.

What is the effective difference between boxing and unboxing in C#?

Unboxing extracts the value type from the object. Boxing is implicit; unboxing is explicit. The concept of boxing and unboxing underlies the C# unified view of the type system in which a value of any type can be treated as an object. In the following example, the integer variable i is boxed and assigned to object o .


1 Answers

It looks like what you are really doing here is comparing manual boxing with inbuilt boxing. The inbuilt boxing has been highly optimised - so I wouldn't expect to see a huge difference here, but we can check. Importantly, note that both have the same memory impact: one heap object containing one int field, per int boxed/wrapped.

The following shows pretty-much identical times for the two approached; I would say, therefore, just box it the direct / inbuilt way.

Note: run it in release mode, without a debugger (ideally at the command line). Note the first call is there to pre-JIT everything.

using System;
using System.Diagnostics;
public sealed class IntObj
{
    public readonly int Value;
    public IntObj(int value)
    {
        Value = value;
    }
}
static class Program
{
    static void Main()
    {
        Run(1, 0, false);
        Run(100000, 500, true);
        Console.ReadKey();
    }
    static void Run(int length, int repeat, bool report)
    {
        var data = new object[length];

        int chk = 0;
        var watch = Stopwatch.StartNew();
        for (int j = 0; j < repeat; j++)
        {
            for (int i = 0; i < data.Length; i++)
            {
                data[i] = i;
                chk += i;
            }
        }
        watch.Stop();
        if(report) Console.WriteLine("Box: {0}ms (chk: {1})", watch.ElapsedMilliseconds, chk);
        chk = 0;
        watch = Stopwatch.StartNew();
        for (int j = 0; j < repeat; j++)
        {
            for (int i = 0; i < data.Length; i++)
            {
                chk += (int) data[i];
            }
        }
        watch.Stop();
        if (report) Console.WriteLine("Unbox: {0}ms (chk: {1})", watch.ElapsedMilliseconds, chk);

        chk = 0;
        watch = Stopwatch.StartNew();
        for (int j = 0; j < repeat; j++)
        {
            for (int i = 0; i < data.Length; i++)
            {
                data[i] = new IntObj(i);
                chk += i;
            }
        }
        watch.Stop();
        if (report) Console.WriteLine("Wrap: {0}ms (chk: {1})", watch.ElapsedMilliseconds, chk);
        chk = 0;
        watch = Stopwatch.StartNew();
        for (int j = 0; j < repeat; j++)
        {
            for (int i = 0; i < data.Length; i++)
            {
                chk += ((IntObj)data[i]).Value;
            }
        }
        watch.Stop();
        if (report) Console.WriteLine("Unwrap: {0}ms (chk: {1})", watch.ElapsedMilliseconds, chk);
    }


}
like image 77
Marc Gravell Avatar answered Oct 13 '22 03:10

Marc Gravell