Value types are created on the stack. Reference types are
created on the heap. When something is created on the heap (an
object) the variable assigned to that object holds a 4 byte “pointer”
to the address space on the heap where the object has been
allocated. Every time you pass that variable as a parameter to
another method, the 4 byte pointer is passed, not the object
itself. When you pass a value type (Integer, DateTime and such),
a copy is made and the entire value type is copied to the method where
its going to be used.
In the near future, I have a post in the making on using value types versus reference types.
Sometimes, you need to use a value type as if it were a
reference type. This is known as “boxing”. Let’s say you
wanted to create an arraylist that contains Integers.
If you examine the Add method of an arraylist, you see that it is
not overloaded. It only take System.Object as a parameter.
System.Object is a reference type is any objects are created on the
heap. In the first paragraph, we know that Int32 is a value
type. So what happens when we add an integer to an
arraylist? Let’s look at the MSIL
At L_0008, you see that we load the 4 byte integer 10 to the stack,
you see the IL instruction to box that value as the next
instruction. So what is actually being stored in the
arraylist? Well we know that since arraylist takes an object as
its parameter, we know that it wants to store an address pointer, not
the value ‘10’. In order to get an address pointer to store in
the arraylist, the integer has to be converted to an object and a
reference to that object must be obtained. This is called boxing.
So what is really happening during boxing? Just like any
object, memory on the heap must be allocated for the object. The
Int32’s information is then copied to that new address space. The
address pointer of that location where the Int32’s information was
copied to is returned. The Int32, a native value type, is now an
object: a reference type. That address pointer is what actually
gets passed to the Add method of the arraylist.
So what about unboxing? Unboxing is the exact opposite of boxing.
In this code, we create an Int32 and want to store the value from
the first element of the arraylist to this Integer, in this case
‘10’. Unboxing is defined as getting the address of the object,
and then copying that information to a value type that has been created
on the stack (b in the above example). The MSIL is below:
You can see at instruction L_001c, the FromObject method is
called. This does the work of unboxing that we mentioned
above. 2 imporant exceptions to take note of when unboxing
though. If the reference that are “getting” from the arraylist is
nothing, a NullReferenceException will occur.
If the reference type that you are “getting” isn’t an Int32 in the
above example, let’s say its a System.DateTime, then a InvalidCastException will occur.
So you’ve probably heard to avoid boxing and unboxing when you
can. Why? Obviously, its costly to the speed and memory of
your application. Extra instructions and memory space are
required when boxing and unboxing. Also when you box a value type
(recall this required allocating memory space on the heap), you always
risk having the garbage collector run against the heap to clean up
unused resources, which is an expensive operation.