The Art of Debugging – A Developer’s Best Friend – Lesson 8 – The Garbage Collector – GC – Repost

Download the sample project – debugging.zip

Garbage collection in the Microsoft .NET common language runtime environment completely absolves the developer from tracking memory usage and knowing when to free memory.

However, you'll want to understand how it works.

It is important to know how resources are allocated and managed, and how the garbage collection algorithm works.

How the garbage collector identifies objects to free from memory

The garbage collector checks to see if there are any objects in the heap that are no longer being used by the application.

If such objects exist, then the memory used by these objects can be reclaimed.

If no more memory is available for the heap, then the new operator throws an OutOfMemoryException.

It is not trivial for the garbage collector know if an application is using an object or not.

When you use the new operator

Each time you use the new operator to create an object, the runtime allocates memory for the object from the managed heap.

As long as address space is available in the managed heap, the runtime continues to allocate space for new objects.

One memory gets low

Memory is not infinite.

Eventually the garbage collector must perform a collection in order to free some memory.

The garbage collector's optimizing engine determines the best time to perform a collection, based upon the allocations being made.

As stated previously, when the garbage collector performs a collection, it checks for objects in the managed heap that are no longer being used by the application and performs the necessary operations to reclaim their memory.

The garbage collector improves performance by using generations

One feature of the garbage collector that exists purely to improve performance is called generations.

A generational garbage collector takes into account two facts that have been empirically observed in most programs in a variety of languages:

Assumptions made by the garbage collector

Newly created objects tend to have short lives.

The older an object is, the longer it will survive.

How the garbage collector groups objects

Generational collectors group objects by age and collect younger objects more often than older objects.

When initialized, the managed heap contains no objects.

All new objects added to the heap can be said to be in generation 0, until the heap gets filled up which invokes garbage collection.

As most objects are short-lived, only a small percentage of young objects are likely to survive their first collection.

Surviving collection and moving to the next generation – generation 1

Once an object survives the first garbage collection, it gets promoted to generation 1.Newer objects after GC can then be said to be in generation 0.The garbage collector gets invoked next only when the sub-heap of generation 0 gets filled up.

All objects in generation 1 that survive get compacted and promoted to generation 2.

All survivors in generation 0 also get compacted and promoted to generation 1.

Generation 0 then contains no objects, but all newer objects after GC go into generation 0.

What developers should care about

It is better to have your objects in lower generations, such as generation 0 or 1. That way there is a higher likelihood that they will be collected and memory will be freed.

The purpose of this blog

While all the background? Knowing which generation our objects reside in is a big help.

Knowing that our objects on not being garbage collected is critical to managing memory efficiently.

That is the main function of this part of the blog.

Currently, there is no built in way to determine the generation of an object that needs to be collected.

Our goal – to determine the generation of the “bytes” as it’s array

The .net framework contains a class called GC. This might be a good starting point to determine which generation our object is in.

Notice below that we are building a string builder object. It is called SB. We would expect that this object is in generation zero right after we step over its allocation in the debugger.

There is a method in the GC class called GetGeneration. This method takes as a parameter the object whose generation we wish to determine.

We can do this directly from the watch window.

clip_image002

Notice that intellisense allows us to select the appropriate method.

clip_image004

As we would expect, the sb object is in fact in generation 0.

clip_image006

Notice that we can also apply our object ID is that we previously defined.

Recall that this object referrers to our main form.

Notice that it is now in generation one, meaning is survived the sweep by the garbage collector.

Too many objects in higher generations can lead to real performance problems.

Too many objects in generation two, for example, can cause the garbage collector to work too hard during low memory situations.

Your application may experience lots of disk swapping and high CPU utilization in this situation.

This may cause your application to the CPU starved and it will perform poorly.

clip_image008

The goal of this blog was to teach you more about the garbage collector.

And despite the fact that the built in debugger doesn't provide useful generational information, I have provided the means by which you can determine which generation your object resides in.