CHAPTER 13 UNDERSTANDING OBJECT LIFETIME
Exactly how this garbage collection occurs, however, depends on which version of the .NET
platform your application is running under. You’ll look at the differences a bit later in this chapter.
Setting Object References to null
C/C++ programmers often set pointer variables to null to ensure they are no longer referencing
unmanaged memory. Given this, you might wonder what the end result is of assigning object references
to null under C#. For example, assume the MakeACar() subroutine has now been updated as follows:
static void MakeACar()
{
Car myCar = new Car();
myCar = null;
}
When you assign object references to null, the compiler generates CIL code that ensures the
reference (myCar, in this example) no longer points to any object. If you once again made use of
ildasm.exe to view the CIL code of the modified MakeACar(), you would find the ldnull opcode (which
pushes a null value on the virtual execution stack) followed by a stloc.0 opcode (which sets the null
reference on the variable):
.method private hidebysig static void MakeACar() cil managed
{
// Code size 10 (0xa)
.maxstack 1
.locals init ([0] class SimpleGC.Car myCar)
IL_0000: nop
IL_0001: newobj instance void SimpleGC.Car::.ctor()
IL_0006: stloc.0
IL_0007: ldnull
IL_0008: stloc.0
IL_0009: ret
} // end of method Program::MakeACar
What you must understand, however, is that assigning a reference to null does not in any way force
the garbage collector to fire up at that exact moment and remove the object from the heap. The only
thing you have accomplished is explicitly clipping the connection between the reference and the object
it previously pointed to. Given this point, setting references to null under C# is far less consequential
than doing so in other C-based languages; however, doing so will certainly not cause any harm.
The Role of Application Roots
Now, back to the topic o f how the garbage collector determines when an object is no longer needed. To
understand the details, you need to be aware of the notion of application roots. Simply put, a root is a
storage location containing a reference to an object on the managed heap. Strictly speaking, a root can
fall into any of the following categories:
•
References to global objects (though these are not allowed in C#, CIL code does
permit allocation of global objects)
•
References to any static objects/static fields
•
References to local objects within an application’s code base
477