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>
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.
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++.
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.
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 .
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);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With