#941 – Checking to See If Objects Are Disposable

If a type implements the IDisposable interface, you should always call the Dispose method on an instance of the class when you are done using it.  The presence of IDisposable indicates that the class has some resources that can be released prior to garbage collection.

Below is one pattern for checking to see if an object implements the IDisposable interface.

            Dog bob = new Dog("Bob", 5);
            if (bob is IDisposable)

You can also use the using statement to automatically call Dispose on an object when you’re done using it.

#940 – Finalizers Are Called when an Application Shuts Down

A finalizer is an override of the System.Object.Finalize method that you implement using the destructor syntax.  The finalizer is called automatically by the garbage collector, before it releases memory for the object.

Finalizers are also called when an application shuts down.  Before the application shuts down, the finalizers of any objects that still exist on the managed heap are called.  Note that this is only true if the application shuts down in a controlled manner.  If the application crashes, the finalizers will not be called.

#939 – Not All Objects on Heap Are Promoted to Next GC Generation

Objects on the managed heap are grouped into generations by the garbage collector (GC), as follows:

  • Generation 0 – Objects that have been created since the last GC pass  (newest objects)
  • Generation 1 – Objects that have survived one pass of the GC
  • Generation 2 – All other objects  (oldest objects)

Objects are only promoted to the next generation if the generation that they are currently located in is examined and collected during a garbage collection pass.

This means:

  • Since the GC always examines Gen 0 during any GC pass, Gen 0 objects that survive a garbage collection are always promoted to Gen 1.
  • Objects in Gen 1 are only promoted to Gen 2 if Gen 1 is examined and collected during a GC pass and the object survives.  The GC will very often do only a Gen 0 pass during collection.  When the GC only examines and collects Gen 0, Gen 1 objects are not examined and therefore not promoted to Gen 2.

#938 – Finding Out What GC Generation an Object Is In

The garbage collector (GC) groups objects into generations to avoid having to examine and collect all objects in memory whenever a garbage collection is done.

For debugging purposes, it’s sometimes useful to know which generation an object currently belongs to.  You can get this information using the GC.GetGeneration method, as shown below.

            Dog bob = new Dog("Bob", 5);
            Console.WriteLine(string.Format("Bob is in generation {0}", GC.GetGeneration(bob)));

            Console.WriteLine(string.Format("Bob is in generation {0}", GC.GetGeneration(bob)));

            Console.WriteLine(string.Format("Bob is in generation {0}", GC.GetGeneration(bob)));

In the example above, the “Bob” Dog object starts out in generation 0. After we do the first garbage collection, it’s promoted to generation 1 and after the 2nd collection, it’s promoted to generation 2.

#937 – Forcing a Garbage Collection

The garbage collector (GC) normally runs automatically, doing a garbage collection pass when necessary (when there is memory pressure and you are allocating memory for some new object).

You typically just let the garbage collector run automatically, never explicitly asking it to do garbage collection.

For testing purposes, however, you might want to force garbage collection to happen at a particular time.  You can do this by calling the GC.Collect method.  Calling Collect will force a collection across all generations.  You can also specify the highest generation to collect as follows:

  • GC.Collect() – Collect generations 0, 1, 2
  • GC.Collect(0) – Collect generation 0 only
  • GC.Collect(1) – Collect generations 0, 1

Objects with finalizers will not be collected when you call Collect, but rather placed on the finalization queue.  If you want to also release memory for these objects, you need to wait until their finalizers are called and then do another garbage collection pass.


#936 – Visualizing Garbage Collection Generations

The garbage collection groups objects on the managed heap into generations.  This improves the performance of the garbage collector (GC), since it typically collects objects in Generation 0 (newest), only moving to older generations if necessary.

Below is an example of this.  To start with, we have an empty managed heap (no objects).  The entire heap is considered Generation 0, since we haven’t yet done a garbage collection.


We now allocate three Dog objects on the heap.  They are allocated in the first available space within Gen 0.


We now set the yourDog reference to null, so that Jack is no longer referenced.  Before garbage collection, the heap looks like this:


Assume that a GC pass runs now and collects objects in Gen 0 (the only generation available).  Memory for Jack is released, everything in Gen 0 is compacted, and whatever remains is marked as Gen 1.  Gen 0 now starts again at the free space pointer.


Assume that we run for a while and allocate a couple more Dog objects–Lassie and Rin Tin Tin.  Then assume that the reference to Lassie is removed and that the reference to Ruby is also removed.  Before collection, the heap looks as follows.  Notice that there are unreachable objects in both Gen 0 and Gen 1.


Assume that a garbage collection now runs and collects only Gen 0.  Memory for Lassie is reclaimed, Gen 0 is compacted and and its objects are promoted to Gen 1.  The existing Gen 1, however, is not collected and its objects remain in Gen 1.


Finally, let’s assume that the garbage collection runs one more time.  It begins with Gen 0, but there is nothing to collect.  Let’s assume that there are high memory demands that cause the GC to decide to also collect Gen 1.  It can now release memory for Ruby and then compacts Gen 1 and promotes its surviving objects to Gen 2.


#935 – Large Objects Are Allocated on the Large Object Heap

The managed heap is the area in memory where reference-typed objects are allocated.  When you create a new object, a portion of the managed heap is allocated for the object.

In reality, objects are stored on either the Small Object Heap (SOH) or the Large Object Heap (LOH).  Objects that are larger than 85,000 bytes are allocated on the LOH.  All other objects are allocated on the SOH.

Other differences between the two heaps:

  • The SOH is generational–objects belong to generation 0, 1, or 2.  The LOH is not sub-divided into generations
  • The LOH is only garbage collected when generation 2 of the SOH is collected.  (I.e. Rarely)
  • After the LOH is garbage collected, the heap is not compacted.  This results in the memory becoming fragmented and requires maintaining a linked list of free blocks.  (The SOH is compacted after every collection).
  • Allocation on the LOH can be slower than the SOH, due to the fragmentation.

#934 – How Generations Help the Garbage Collector Run More Efficiently

Objects allocated on the managed heap are grouped into generations by the garbage collector:

  • Generation 0 – Newest objects
  • Generation 1 – Objects that have survived one GC pass
  • Generation 2 – Objects that have survived more than one GC pass

When the garbage collector performs a GC pass, it looks only at objects in generation 0, releasing memory for any that are no longer reachable.  In this way, the garbage collector is more efficient, because it is only looking at a portion of the managed heap.

If the garbage collector has collected Gen 0, but the application requires more memory, the garbage collector can then garbage collect generation 1.  If the application still requires memory after collecting generation 1, it can move on to generation 2.

This scheme relies on the fact that if an object survives one GC pass, it likely has a longer lifetime and will survive future passes.

#933 – The Garbage Collector Groups Objects into Generations

Referenced-typed objects in an application have different lifetimes.  The application will use some objects as long as the application is running.  Others are referenced only during execution of a single method.

If the garbage collector always examined every object whenever it did a garbage collection pass, it would spend a lot of time reexamining longer-living objects that can’t yet be garbage collected.  The garbage collector can perform more efficiently by looking at only a subset of all objects during each pass.  It does this by grouping objects into generations:

  • Generation 0 – Objects that have been created since the last GC pass  (newest objects)
  • Generation 1 – Objects that have survived one pass of the GC
  • Generation 2 – All other objects  (oldest objects)

The garbage collector examines and collect objects in generation 0, moving to higher generations only if it needs additional memory.

Objects are promoted to the next generation only if a GC pass is done on the generation in which they are located.

#932 – When Objects Become Eligible for Garbage Collection

In general an object can be garbage collected when it is no longer referenced by any other object or reference-typed variable.  For example, the Dog object named “Kirby” is no longer referenced in the code snippet below when the myDog variable is set to null.

            Dog myDog = new Dog("Kirby", 15);

            Dog yourDog = new Dog("Ruby", 3);

            // Kirby no longer referenced after this line executes
            myDog = null;

In practice, however, an object may become eligible for collection earlier than you think.  In the code sample above, the “Kirby” object will not be referenced at any time after the first call to the Bark method.  This means that the compiler may decide to garbage collect the “Kirby” object after the call to this method, i.e. before myDog is actually set to null.