Click here to Skip to main content
15,881,089 members
Articles / Programming Languages / C#
Article

GC 102

Rate me:
Please Sign up or sign in to vote.
4.33/5 (14 votes)
2 Mar 20042 min read 58.1K   26   5
Further notes on programming for the Garbage Collector.

Introduction

In GC 101,  I discussed the reasons for Finalize and Dispose, and how to implement these methods in your components. The C# language has some nice built-in functionality to help you with the Disposing pattern, which I will discuss here.

Cool C# feature: using

Consider the following code:

C#
SqlConnection cn = new SqlConnection(cnString);
cn.Open();
//Use the open connection
cn.Dispose();

If an exception had to be thrown on the call to Open, Dispose will never get called, and your resource might leak. I'm sure you already know the solution:

C#
try
{
    SqlConnection cn = new SqlConnection(cnString);
    cn.Open();
    //Use the open connection
}
finally
{
    cn.Dispose();
}

This code does exactly what the first listing does, but is safer - you are guaranteed that Dispose will be called. But, it is also much less readable! C# has a nice feature to help with readability here: the using clause. Our code can be rewritten as:

C#
using (SqlConnection cn = new SqlConnection(cnString))
{
    cn.Open();
    //Use the open connection
}

Lovely, isn’t it? As soon as the using block exits, Dispose will automatically be called on all objects that implement IDisposable and are created with the using-clause. If you look at the compiler-generated IL, you will see that a try - finally is actually implemented.

Cool C# feature: foreach

You might have collections of expensive (disposable) objects from time to time. To ease coding against your collection, have it implement IDisposable:

C#
internal class openDBConnectionsEnumerator : IEnumerator, IDisposable
{}

public class openDBConnections : IEnumerable
{
    public IEnumerator GetEnumerator()
    {
        return new openDBConnectionsEnumerator();
    }
}

Now, you can use your collection in a foreach loop, and Dispose is called automatically on your collection when the loop exits:

C#
OpenDBConnections cons = new OpenDBConnections();
foreach(DBConnection in cons)
{
    //Do something with connection object
} //Dispose is called on the IEnumerator when loop exits

Performance issues

The GC has only one thread that calls Finalize on all the objects in the finalization queue, and thus might have a tough time in keeping up with Finalizable objects created by more than one user thread. A shortened overview of a Finalizable object’s lifespan:

Image 1

There are actions here that impacts negatively on performance:

  1. Enlisting in the Finalization queue
  2. Removing from Finalization queue to be enlisted in To Be Finalized queue
  3. Calling Finalize on the component
  4. Removing from To Be Finalized queue

It should be obvious that, if possible, the shortcut should be taken, and Finalizable components avoided. To do so, and this is quite important:

  1. Don’t create Finalizers (or destructors) for your components unless absolutely necessary.
  2. For components where you do need a destructor, always call Dispose on your component when appropriate. This suppresses the GC's call to Finalize and saves you the overhead of calling Finalize and enlisting in the To Be Finalized queue.

Threading

A component’s Dispose(bool) method should never be called from both the GC’s finalizer thread and a user thread. There may be instances where more than one user thread calls the method. In this case, make your cleanup code thread safe in exactly the same way you’d make any code thread safe. If you are 100% sure that your code will not be called by more than one user thread at a time, don’t enforce thread-safety, as this impacts negatively on performance.

(You will also find this article on my blog).

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
South Africa South Africa
Ernst develops software for the agricultural industry.
He moderates the SADeveloper INETA community, and gives talks on development-related stuff from time to time.
He is an MVP in Visual C#, but whilst he advocates the adoption of .NET, he is also skilled in non-Microsoft technologies.
Sometimes he chats about it.

Comments and Discussions

 
GeneralIncorrect code example Pin
Staffan O9-Mar-04 21:34
Staffan O9-Mar-04 21:34 
GeneralRe: Incorrect code example Pin
Ernst Kuschke10-Mar-04 19:55
Ernst Kuschke10-Mar-04 19:55 
GeneralRe: Incorrect code example Pin
dzCepheus14-Mar-04 19:40
dzCepheus14-Mar-04 19:40 
Generalforeach does not call Dispose on collection, but on enumerator Pin
Frank Hileman9-Mar-04 3:28
Frank Hileman9-Mar-04 3:28 
GeneralRe: foreach does not call Dispose on collection, but on enumerator Pin
Ernst Kuschke21-Apr-04 8:29
Ernst Kuschke21-Apr-04 8:29 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.