Behind the Code: Stacks and Heaps - Page 3
       by kirupa  |  29 March 2007

In the previous page, you learned about heaps and, more importantly, how unused data in both your heap and stack is dealt with. Let's pick up from where we left off and continue discussing garbage collectors.

Garbage Collection (Continued)
There are numerous approaches garbage collectors take when attempting to optimize free space, and that depends on your language and runtime environment. Visual Basic 6 and earlier used a reference counting approach where you count the number of references each object on the heap has pointing to it, but (as far as I know) .NET uses a reference tracing approach. Most algorithms that attempt reference tracing build a tree of all objects based on entry points in your application called roots. Any objects that don't make it onto the tree are assumed to be wasted space, so they are quickly cleaned up.

The actual GC implementation in the .NET VM's may go several steps beyond what I explained, and there are various topics that I will not cover in this article such as dealing with fragmentation or how objects get prioritized for removal. If you are curious to learn more about these topics, the following course/lecture notes from a good class discussing programming languages may come in handy.

Using the = Operator with Reference Types
With value types, when you set one variable equal to another variable, the actual data gets copied. For example, take a look at the following code:

static void Main()
{
int x = 10;
int y = x;
 
x = 5;
 
// x = 5
// y = 10
}

I set the y variable equal to x, and I then change the value of x to be 5. In the end, the values stored by x is 5 and the value stored by y is 10. This is just what we want! With reference types, though, setting one variable equal to another variable only transfers the reference to the same object on the heap.

Let's look at a demo of what I am referring to:

class Simpsons
{
public string name;
public int age;
}
 
public void People()
{
Simpsons bart = new Simpsons();
Simpsons bort = bart;
 
bart.name = "Bart";
bart.age = 11;
 
bort.name = "Bort";
bort.age = 22;
}

In the above example, I create two objects called bort and bart. The thing to note is that the bort object is set equal to the bart object, and I then proceed to populate the fields in the bort and bart objects. When I Console.WriteLine bart's name as in bart.name, what is the output you get? What should be the output you want?

The output for bart.name will be Bort. The output you would have wanted would have been Bart. The reason for this goes back to the difference between value and reference types that I briefly mentioned earlier and in the first page. Let's look at both the stack and heap for the above example:

Do you see the issue? Both the bort and bart objects are referencing the same thing! By setting bort equal to bart, what I essentially did was set the bort reference equal to the bart reference. That brings us full-circle back to a simple fact of programming in .NET and most other languages: reference types store references and value types store values!

Before this tutorial ends, you can solve the above equals problem by initializing the bort value to be a new Simpsons object as in:

Simpsons bort = new Simpsons();

Just a final word before we wrap up. If you have a question and/or want to be part of a friendly, collaborative community of over 220k other developers like yourself, post on the forums for a quick response!

Kirupa's signature!

 

1 | 2 | 3




SUPPORTERS:

kirupa.com's fast and reliable hosting provided by Media Temple.