Bill Blogs in C# -- GC

Bill Blogs in C# -- GC

Created: 3/22/2010 5:54:48 PM

I received this feedback on the Safari site about an earlier draft of the 2nd Edition of Effective C#:

Text says: “You’ll notice that neither MyResourceHog nor DerivedResourceHog contain a finalizer. The example code I wrote does not directly contain any unmanaged resources. Therefore, a finalizer is not needed. That means the example code never calls Dispose(false). That’s the correct pattern. I take this to mean all I need is (assuming I need a finalizer):

~MyResourceHog()
{
    Dispose(false);
} “

Is that it? What should be done in dervied classes? Please elaborate on this just a bit more and also include the finalizer in the code, just comment it out, so we can see the full pattern for the base and dervied classes. Thanks!

I intentionally did not include an example where you included a finalizer. In the vast majority of cases, you won’t include a finalizer. If you types do not include unmanaged resources, you don’t ever need to add a finalizer. This is also explained in “Framework Design Guidelines”, pp319-322.  The important reason for not including a finalizer (when you don’t need one) is that the presence of a finalizer (even if you call GC.SuppressFinalization()) affects performance. If it’s not needed, its presence is a needless performance robber.

And, if you do need a finalizer, you always need to implement IDisposable. Then, your finalizer is always as simple is shown above.

I chose not to include the expanded sample because I didn’t want to create and show a sample that would lead to a bad practice.

Created: 11/2/2007 11:35:00 AM

Brian Grunkmeyer has written a rather deep article for the BCL weblog that discusses many of the pitfalls that surround finalization, dispose, and weird things that can happen during the birth, death, and possible resurrection of an object:

 http://blogs.msdn.com/bclteam/archive/2007/10/30/dispose-pattern-and-object-lifetime-brian-grunkemeyer.aspx

 Some of the important points he covers:

. What happens if an object's constructor thorws an exception?

. What happens if an object's finalizer is called as part of an AppDomain unloading?

. Why should I care?

. What can I do to prevent exceptions and application terminations?

Created: 10/3/2005 11:44:32 PM
A question with two answers: No, and Occasionally.

I received this question last week:

I'm still working through and enjoying "Effective C#", unfortunately  my job has really intruded for the past 2 months. I'm at Item 18: "Implement the standard Dispose pattern". It says that you should  implement this pattern if your class uses non-memory resources, so I went back to some programs I had written using the Windows Forms lib that use Pens, Fonts, etc.

My First Answer:

Regarding (1): You should never hold unmanaged resources in static variables. It makes the lifetime management more or less impossible to get right.

Regarding (2): This is why I said what I said for (1). There is no reliable way to make this work. If you release the resources in an instance's Dispose() method, any other instance is broken: the resource is gone, but the static member variables are still in scope. If you don't release the resources in some instance method, it's broken because you never release the resources.

If you really want one copy of the unmanaged resources, wrap them in a type that implements the Singleton Pattern.

So, don't store unmanaged resources in static variables. Ever. It won't work.

Upon Further Reflection:

I'm still not sure it's a common pattern, but there might be some instances where this might work.  It's a small resource leak, but there are instances where you don't really care.

Suppose you create some type that needs to hold a resource that implements IDisposable, and that type will have a lifetime that mirrors your application's lifetime. Well, then a static member variable means that you only create one copy of that resource in your application. However, you'll never release that resource. However, it will get cleaned up when your app exits. So, no real problem. It's a little fragile, because you will have quite a bit of work to do if your application changes later and your resource's lifetime no longer matches the application's lifetime.

When I went to implement the pattern I got confused. My questions are
1) In my classes my unmanaged resources are held in static vars. What should I do?
2) Assuming that after understanding #1, I still want to write virtual void Dispose(bool isDisposing): Do I need to free all the references I've new'd to objects when "freeing managed resources"? If yes, how?



Created: 2/9/2005 8:00:27 AM
SQLConnection, for one, calls GC.SuppressFinalization() in its constructor. Why would you do that?

A fried of mine asked about the practice of calling GC.SuppressFinalize() in a constructor. He noticed it in the SQLConnection constructor. It’s also present in a number of other components, such as the Windows Forms Datagrid. Is it safe? Why do it?

Calling GC.SuppressFinalize() is a performance optimization that a number of classes that derive from System.ComponentModel.Component use. Personally, I think it can be unsafe, so adopt it with caution.

System.ComponentModel.Component implements IDisposable and provides a finalizer so that all derived classes can cleanup both managed and unmanaged resources.

The pertinent pieces of code are here:

// IDisposable.Dispose:
// delegates the work to Dispose( bool )
// Then, notify the GC that Finalization is no longer needed.
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}

// Finalizer.
// Delegates the work to Dispose( bool )
~Component()
{
this.Dispose(false);
}





// hook for all derived classes:
protected virtual void Dispose(bool disposing) {
// KEY POINT: If called from the finalizer,
// there's nothing to do.
if (!disposing)
{
return;
}
// much other work elided
}

SQLConnection overrides Dispose( bool ) to close the connection when IDisposable.Dispose() is called:

protected override void Dispose(bool disposing) {
if (disposing)
{
switch (this._objectState)
{
case ConnectionState.Open:
{
this.Close();
break;
}
}
this._constr = null;
}
// KEY POINT: Note that there is no 'else' clause.
// No work gets done when called by the finalizer.
base.Dispose(disposing);
}

Just like in Component, nothing actually happens when this is called from the Finalizer. That means the finalizer for SQLConnection doesn't really need to be called under any circumstances, even when the user forgets to call IDisposable.Dispose()

Well, Finalizers extract a rather heavy performance penalty on the garbage collector. And, sometimes people forget using clauses, or calling Dispose() diligently. So, the constructor for SQLConnection calls GC.SuppressFinalization( this ) so that the GC ignores the presence of the finalizer, and you don't need to pay the performance penalty if you forget to call IDisposable.Dispose().

This technique is correct only because:

  1. SQLConnection is sealed, so no one can create a class derived from SQLConnection that actually does work when the finalizer executes.
  2. SQLConnection, and all base classes: System.ComponentModel.Component, System.MarshalByRefObject, and System.Object do not perform any cleanup in their finalizers.

The reason I find this a bit unsafe is that it's entirely possible for someone to add code breaking (2) above in some future release. I don't advocate it for general use. But, SQLConnection gets used a lot, and here, the performance costs probably add up. And, hopefully, if one of the base classes does make that change, everyone gets notified.

I'll close with my own question: Why doesn't SQLConnection need to do any work in its finalizer? Once again, if you use Reflector, you'll see quite a bit of code in the Close() method. What happens if that never gets called? If you know, please contact me.



Implement the Standard Dispose Idiom
I covered this in depth in Effective C#
Created: 12/24/2004 2:00:18 AM
Quote: "Why should a developer building "business solutions" ever care about closing a connection to a database, or even opening it?"

Eugenio has an interesting take on IDisposable, or the needs for business developers to actually care about resource acquisition or release.  He sez:

"The "using" statement is one step forward, but not enough in my opinion. In the same way you need to remember closing a connection, you need to remember using "using"."

Interesting stuff. I'm not sure the problem is as big as he makes it out though.  If you forget to close, or Dispose something, it's likely more of a performance error than a resource leak.  Eventually, the finalizer will clean up.  (Yes, I can construct code that makes it a fatal bug, but it's not often occurring in practice.)

It would be nice to create a class that had deterministic finalization, when needed though.



Eugenio's post
More on IDisposable.
Created: 12/8/2004 6:47:29 PM
Always close files and streams

Question:

I read your article Manage C# Objects in Visual Studio magazine.

I'm having a problem using the XmlDataDocument class and was wondering if you think this is a situation where I should use IDisposable as described in your article.  The way the form works is the user will make changes and then click a "Save" button, or other events will trigger a save, which should persist changes to the XML file.

Thanks in advance for your help.

class frmMain : System.Windows.Forms.Form
{
  //code omitted

  string xmlSchema = (@"C:\Projects.xsd");
  string xmlFile = (@"C:\Projects.xml");
  XmlDataDocument xdd = new XmlDataDocument();

  public frmMain()
  {
    InitializeComponent();
    xdd.DataSet.ReadXmlSchema(xmlSchema);
    // load xml data
    XmlTextReader xrd = new XmlTextReader(xmlFile);
    xrd.MoveToContent();
    xdd.Load(xrd);
  }
 
 private void btnAddCfg_Click(object sender, System.EventArgs e)
 {                
   DataTable cfgTbl = xdd.DataSet.Tables["Configuration"];
   DataRow newCfg = cfgTbl.NewRow();
   newCfg["ConfigName"] = "NewConfiguration";
   cfgTbl.Rows.Add(newCfg);
   xdd.Save(xmlFile); // ç Error here: "The process cannot access the
   // file "C:\Projects.xml" because it is being used by
   // another process."
 }
}

Answer: Well, the answer is rather simple:  You never closed the file. When the constructor exits, the XmlTextReader is garbage. Eventually, the .NET Garbage Collector will reclaim that memory.  However, before the GC can reclaim the memory, it will call the finalizer for the XmlTextReader.  That will close the file.  If you wait long enough, the file does get closed.  Long enough is a non-deterministic amount of time.

To fix the problem, you need to explicitly close the file.  You also need to make sure that you close the file, even if an exception gets thrown in your constructor.  That means a using clause, or a finally clause. Your constructor should look like this:

public frmMain()
{
  InitializeComponent();
  xdd.DataSet.ReadXmlSchema(xmlSchema);
  // load xml data
  XmlTextReader xrd = null;
  try {
    xrd = new XmlTextReader(xmlFile);
    xrd.MoveToContent();
    xdd.Load(xrd);
  } finally
  {
    if ( xrd != null )
      xrd.Close( );
  }
}

You can’t put the XmlTextReader in a using clause, because it does not support IDisposable, even though it has a Close() method.

Changing it in this manner ensures that the file is always closed before the constructor exits.  That’s all there is to it.

I hope that helps.  Follow the link below for much more on disposing and closing objects (from my new book, Effective C#)



Implement the Standard Dispose Idiom
Not exactly what he's seeking, but close
The original aticle
The article referenced in the question
Created: 4/20/2004 6:11:15 AM
Wasn't this supposed to be easier?

Hi Bill

I am an independent MSCD for Microsoft .NET, and I always enjoy your writing.

Your article beautifully explains the Dispose application implementation pattern. However, there is one important aspect which you do not address and which, in the whole MSDN library, is only documented with one single sentence: "Developers must propagate Dispose throughout a containment hierarchy to ensure that children of a component also free resources".

It took me a lot of research to 1) find this best practice rule and 2) figure out what Microsoft most probably means by it. The words "containment hierarchy", "children" and "component" can mean many different things, depending on whether you look at it strictly from the .NET Framework or from a more general OOP point of view.

In my interpretation, the rule applies strictly to any class who

implements System.ComponentModel.IComponent (such as System.Data.DataSet) and

has children who also implement System.ComponentModel.IComponent (such as System.Data.DataTable) who

depend on the parent through an intermediate class who implements System.Collections.IEnumerable (such as System.Data.DataTableCollection).

Knowing this rule has important consequences. As to the consumers of disposable classes, it saves them a lot of coding because they only have to dispose the DataSet explicitly, but not all the DataTables. The same is true for Forms and their Controls. On the other hand, if a disposable class is not an IComponent, or if a disposable class has dependent objects who are not in an aggregation relationship to the class, they must call Dispose on each and every dependent object explicitly. As to the developers of disposable classes, they must apply additional best practices if their class is an IComponent who in some way contains other enumerable IComponents.

If you check the Internet discussion threads, you will see that many programmers struggle with the best practices regarding IDisposable. I hope that Microsoft will document this more clearly, or maybe you will address this aspect in one of your future articles.

Best regards

Marc

======================== My Response ==========================

Marc,

First, let me address a couple knits: IComponentModel is derived from IDisposable. For that reason, your recommendations about IComponentModel are in line with what I said, only for IDisposable.

Let me address your second point, about disposing only what you need, and exactly what you need. Much of the confusion comes from many developers' internalizing C++ destructor rules. IDisposable is different: it is legal to dispose of an object more than once. As a class author, that means you must handle the case where an object gets is disposed method called multiple times. For your specific example, it is legal to dispose of every DataTable in a DataSet. It's inefficient and unnecessary, but it is legal and will do no harm.

As a class user, it's a little fuzzier. You should Dispose of those objects you "own", ownership being a fuzzy term in .NET. In your example, the DataSet "owns" the DataTables, so the DataSet disposes of them. Your form "owns" the DataSet, and disposes of it. The Form does not own the DataTable, so no extra dispose is needed.

But like I said, ownership in .NET is a bit fuzzy. Consider this snippet:

public void AddSettingsTable( Dataset s )

{

DataTable t = new DataTable( "Settings" );

AddColumns( t );

s.Tables.Add( t );

}

The Dataset, s, owns the table now, even though you created it in your form.

In short, you're right, if "containment" means "members whose lifetime matches the containing object". Further, you should substitute IDisposable for IComponent, as that is more correct.

Thank you for the letter, I'm glad you liked the article.



C# Pro article on Memory Management
The source article on the subject

Current Projects

I create content for .NET Core. My work appears in the .NET Core documentation site. I'm primarily responsible for the section that will help you learn C#.

All of these projects are Open Source (using the Creative Commons license for content, and the MIT license for code). If you would like to contribute, visit our GitHub Repository. Or, if you have questions, comments, or ideas for improvement, please create an issue for us.

I'm also the president of Humanitarian Toolbox. We build Open Source software that supports Humanitarian Disaster Relief efforts. We'd appreciate any help you can give to our projects. Look at our GitHub home page to see a list of our current projects. See what interests you, and dive in.

Or, if you have a group of volunteers, talk to us about hosting a codeathon event.