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.
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.
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!