Improving .NET Application Performance Part 5: Finalize and Dispose

In our last article we discussed some guidelines to optimize Garbage Collection. The garbage collector provides two more additional methods; Finalize and Dispose. We’ll discuss the guidelines for these methods in this article.

Finalize

Some objects require additional cleanup because they use unmanaged resources that need to be released. This is handled by finalization. An object registers for finalization by overriding the Object.Finalize method.

An object’s Finalize method is called before the object’s managed memory is reclaimed. This allows you to release any unmanaged resources that are maintained by the object. If you implement Finalize, you cannot control when this method should be called because this is left to the garbage collector.

The finalization process requires a minimum of two collection cycles to fully release the object’s memory. During the first collection pass, the object is marked for finalization. Finalization runs on a specialized thread that is independent from the garbage collector. After finalization occurs, the garbage collector can reclaim the object’s memory.

Keep in mind that there is no guarantee regarding the time or order of object collection. Also, memory resources may be consumed for a large amount of time before being garbage collected.

In C#, implement Finalize by using destructor syntax.

class yourObject {

  // This is a finalizer implementation

  ~yourObject() {

    // Release your unmanaged resources here

    . . .

  }

}

The preceding syntax causes the compiler to generate the following code.

class yourObject {

  protected override void Finalize() {

  try{

    . . .

  }

  finally {

    base.Finalize();

  }

}

Dispose

For types that contain references to external resources that need to be explicitly freed by the calling code you would use the Dispose method. You can avoid finalization by implementing the IDisposable interface and by allowing your class’s consumers to call Dispose.

Try to avoid finalization because it is handled asynchronously and unmanaged resources might not be freed in a timely fashion. This is especially important for large and expensive unmanaged resources such as bitmaps or database connections. With this approach, resources are reclaimed as soon as Dispose is called and the object does not have to be queued for finalization. You want to see almost all of your finalizable objects being disposed and not finalized.

To prevent the garbage collector from requesting finalization, your Dispose implementation should call GC.SuppressFinalization.

Close

For certain classes of objects, such as files or database connection objects, a Close method better represents the logical operation that should be performed when the object’s consumer is finished with the object. As a result, many objects expose a Close method in addition to a Dispose method. In well written cases, both are functionally equivalent.

Dispose Pattern

To implement the Dispose pattern, do the following:

  • Create a class that derives from IDisposable.
  • Add a private member variable to track whether IDisposable.Dispose has already been called. Clients should be allowed to call the method multiple times without generating an exception. If another method on the class is called after a call to Dispose, you should throw an ObjectDisposedException.
  • Implement a protected virtual void override of the Dispose method that accepts a single bool parameter. This method contains common cleanup code that is called either when the client explicitly calls IDisposable.Dispose or when the finalizer runs. The bool parameter is used to indicate whether the cleanup is being performed as a result of a client call to IDisposable.Dispose or as a result of finalization.
  • Implement the IDisposable.Dispose method that accepts no parameters. This method is called by clients to explicitly force the release of resources. Check whether Dispose has been called before; if it has not been called, call Dispose(true) and then prevent finalization by calling GC.SuppressFinalize(this). Finalization is no longer needed because the client has explicitly forced a release of resources.
  • Create a finalizer, by using destructor syntax. In the finalizer, call Dispose(false).

C# Example of Dispose

Your code should look like the following.

public sealed class MyClass: IDisposable

{

  // Variable to track if Dispose has been called

  private bool disposed = false;

  // Implement the IDisposable.Dispose() method

  public void Dispose(){

    // Check if Dispose has already been called

    if (!disposed)

    {

      // Call the overridden Dispose method that contains common cleanup code

      // Pass true to indicate that it is called from Dispose

      Dispose(true);

     // Prevent subsequent finalization of this object. This is not needed

     // because managed and unmanaged resources have been explicitly released

      GC.SuppressFinalize(this);

    }

  }

 

  // Implement a finalizer by using destructor style syntax

  ~MyClass() {

    // Call the overridden Dispose method that contains common cleanup code

    // Pass false to indicate the it is not called from Dispose

    Dispose(false);

  }

 

  // Implement the override Dispose method that will contain common

  // cleanup functionality

  protected virtual void Dispose(bool disposing){

   if(disposing){

     // Dispose time code

     . . .

   }

   // Finalize time code

    . . .

  }

  }

Passing true to the protected Dispose method ensures that dispose specific code is called. Passing false skips the Dispose specific code. The Dispose(bool) method can be called directly by your class or indirectly by the client.

If you reference any static variables or methods in your finalize-time Dispose code, make sure you check the Environment.HasShutdownStarted property. If your object is thread safe, be sure to take whatever locks are necessary for cleanup.

Use the HasShutdownStarted property in an object’s Dispose method to determine whether the CLR is shutting down or the application domain is unloading. If that is the case, you cannot reliably access any object that has a finalization method and is referenced by a static field.

protected virtual void Dispose(bool disposing){

  if(disposing){

    // dispose-time code

  . . .

  }

  // finalize-time code

  CloseHandle();

 

  if(!Environment.HasShutDownStarted)

  { //Debug.Write or Trace.Write static methods

    Debug.WriteLine(“Finalizer Called”);

  }

  disposed = true;

}

Finalize and Dispose Guidelines

Let’s summarizes the Finalize and Dispose recommendations:

Call Close or Dispose on Classes that Support It – If the managed class you use implements Close or Dispose, call one of these methods as soon as you are finished with the object.

COM Objects – In server scenarios where you create and destroy COM objects on a per-request basis, you may need to call System.Runtime.InteropServices.Marshal.ReleaseComObject. The Runtime Callable Wrapper (RCW) uses a reference count that is incremented every time a COM interface pointer is mapped to it. The ReleaseComObject method decrements this counter and when it reaches zero, the runtime releases all its references on the unmanaged COM object.

Enterprise Services (COM+) – It is not recommended to share serviced components or COM or COM+ objects in cases where your objects are created in a nondefault context, either because your component is a serviced component configured in COM+ or because your component is a simple COM component that is placed in a nondefault context by virtue of its client. For example, clients such as ASP.NET pages running in a transaction or running in ASPCOMPAT mode are always located inside a COM+ context. If your client is a serviced component itself, the same rule applies.

Crossing a COM+ context boundary is expensive. This issue is increased if your client-side COM+ context has thread affinity because it is located inside an STA. In theses, activate your component, perform work with it, and then release it immediately. When you use Enterprise Services and classes that derive from System.EnterpriseServices.ServicedComponent, you need to call Dispose on those classes.

If the component you call is an unmanaged COM+ component, call Marshal.ReleaseComObject.

The using Statement in C# – The using statement automatically generates a try and finally block at compile time that calls Dispose on the object allocated inside the using block. The following code illustrates this syntax.

using( StreamReader myFile = new StreamReader(“C:\\ReadMe.Txt”)){

       string contents = myFile.ReadToEnd();

       //… use the contents of the file

 

} // dispose is called and the StreamReader’s resources released

During compilation, the preceding code is converted into the following equivalent code.

StreamReader myFile = new StreamReader(“C:\\ReadMe.Txt”);

try{

  string contents = myFile.ReadToEnd();

  //… use the contents of the file

}

finally{

  myFile.Dispose();

}

 

Do Not Implement Finalize Unless Required – Avoid implementing a finalizer or destructor unless finalization is required. Implementing a finalizer on classes that do not require it adds load to the finalizer thread and the garbage collector.

Implement Finalize Only If You Hold Unmanaged Resources across Client Calls – Use a finalizer only on objects that hold unmanaged resources across client calls. For example, if your object has only one method named GetData that opens a connection, fetches data from an unmanaged resource, closes the connection, and returns data, there is no need to implement a finalizer. However, if your object also exposes an Open method in which a connection to an unmanaged resource is made, and then data is fetched using a separate GetData method, it is possible for the connection to be maintained to the unmanaged resource across calls. In this case, you should provide a Finalize method to clean up the connection to the unmanaged resource, and in addition use the Dispose pattern to give the client the ability to explicitly release the resource after it is finished.

Move the Finalization Burden to the Leaves of Object Graphs  If you have an object graph with an object referencing other objects (leaves) that hold unmanaged resources, you should implement the finalizers in the leaf objects instead of in the root object. Moving the finalization burden to leaf objects results in the promotion of only the relevant ones to the finalization queue, which helps optimize the finalization process.

If You Implement Finalize, Implement IDisposable – Implement IDisposable if you implement a finalizer. In this way, the calling code has an explicit way to free resources by calling the Dispose method. You should still implement a finalizer along with Dispose because you cannot assume that the calling code always calls Dispose. Even though this is a costly method, the finalizer implementation ensures that resources are released.

If You Implement Finalize and Dispose, Use the Dispose Pattern – If you implement Finalize and Dispose, use the Dispose pattern as described earlier.

Suppress Finalization in Your Dispose Method – If the calling code calls Dispose, you do not want the garbage collector to call a finalizer because the unmanaged resources will have already been returned to the operating system. You must prevent the garbage collector from calling the finalizer by using GC.SuppressFinalization in your Dispose method.

public void Dispose()

{

  // Using the dispose pattern

  Dispose(true);

  // … release unmanaged resources here

  GC.SuppressFinalize(this);

}

 

Allow Dispose to Be Called Multiple Times – Calling code should be able to safely call Dispose multiple times without causing exceptions. After the first call, subsequent calls should do nothing and not throw an ObjectDisposedException for subsequent calls.

Call Dispose On Base Classes and On IDisposable Members – If your class inherits from a disposable class, then make sure that it calls the base class’s Dispose. Also, if you have any member variables that implement IDisposable, call Dispose on them, too. The following code fragment demonstrates calling Dispose on base classes.

public class BusinessBase : IDisposable{

  public void Dispose() {…}

  protected virtual void Dispose(bool disposing)  {}

  ~BusinessBase() {…}

}

 

public class Customer : BusinessBase, IDisposable{

private bool disposed = false;

 

  protected virtual void Dispose(bool disposing) {

    // Check before calling your Dispose pattern

    if (!disposed){

      if (disposing) {

        // free managed objects

      }

      // free unmanaged objects

      base.Dispose(disposing);

      disposed = true;

    }

  }

Keep Finalizer Code Simple to Prevent Blocking – Finalizer code should be simple and minimal. The finalization happens on a dedicated, single finalizer thread. Do not issue calls that could block the calling thread. If the finalizer does block, resources are not freed and the application leaks memory. Also, Do not use thread local storage or any other technique that requires thread affinity because the finalizer method is called by a dedicated thread, separate from your application’s main thread.

Provide Thread Safe Cleanup Code Only if Your Type Is Thread Safe – If your type is thread safe, make sure your cleanup code is also thread safe. For example, if your thread safe type provides both Close and Dispose methods to clean up resources, ensure you synchronize threads calling Close and Dispose simultaneously.

That’s it for the guidelines on Garbage Collection. In the next article we’ll start discussing threading.