GOTCHA 39 Using Finalize() on disposed objects is costly


GOTCHA #39 Using Finalize() on disposed objects is costly

It is better to Dispose() an object than to depend on its Finalize() being called, because Dispose() lets you control the cleanup of an object (see Gotcha #38, "Depending on Finalize() can tie up critical resources"). Also, there is overhead if the garbage collector needs to call Finalize() (see Gotcha #39, "Using Finalize() on disposed objects is costly"). If an object has been properly disposed of (by the call to Dispose()), there is no need for its Finalize() to be called. After all, Dispose() should have already taken care of its resources, both managed and unmanaged. What would Finalize() need to do in this case?

.NET provides a mechanism (GC.SuppressFinalize()), which tells the CLR not to invoke Finalize() on an object. Calling this method eliminates the overhead of the Finalize() call and the accompanying delay in reclaiming memory.

Let's explore the usage of GC.SuppressFinalize() by studying Example 5-6.

Example 5-6. Suppressing the Finalize() call

C# (SuppressingFinalize)

 using System; namespace SuppressFinalize {     public class Test : IDisposable     {         private readonly int id;         public Test(int theID)         {             id = theID;         }         ~Test()         {     Console.WriteLine("Finalize called on {0}", id);         }         #region IDisposable Members         public void Dispose()         {     Console.WriteLine("Dispose called on {0}", id);     GC.SuppressFinalize(this);         }         #endregion         [STAThread]         static void Main(string[] args)         {             int count = 1;     Test object1 = new Test(count++);     Test object2 = new Test(count++);     object1.Dispose();             Console.WriteLine("Main done");         }     } } 

VB.NET (SuppressingFinalize)

 Public Class Test     Implements IDisposable     Private ReadOnly id As Integer     Public Sub New(ByVal theID As Integer)         id = theID     End Sub     Protected Overrides Sub Finalize()         MyBase.Finalize()         Console.WriteLine("Finalize called on {0}", id)     End Sub     Public Sub Dispose() Implements System.IDisposable.Dispose         Console.WriteLine("Dispose called on {0}", id)         GC.SuppressFinalize(Me)     End Sub     Public Shared Sub Main()         Dim count As Integer = 1         Dim object1 As New Test(count)         count += 1         Dim object2 As New Test(count)         object1.Dispose()         Console.WriteLine("Main done")     End Sub End Class 

In this example, the class Test implements the IDisposable interface. Its Dispose() method invokes GC.SuppressFinalize(). In Main(), you create two objects of Test and dispose of only one of them. When you execute the code, you get the output shown in Figure 5-6.

Figure 5-6. Output from Example 5-6


Note that Finalize() gets called on the second object, but not on the first. When you invoke Dispose() on the first object, you indicate to the CLR that it should not bother invoking Finalize() on this object. As a result, the memory used by the object gets released without the added delay involved with Finalize().

IN A NUTSHELL

Calling Finalize() on an object involves overhead. This should be avoided as much as possible. From within your Dispose() method, call GC.SuppressFinalize().

SEE ALSO

Gotcha #35, "Writing Finalize( ) is rarely a good idea," Gotcha #36, "Releasing managed resources in Finalize( ) can wreak havoc," Gotcha #38, "Depending on Finalize() can tie up critical resources," Gotcha #40, "Implementing IDisposable isn't enough," and Gotcha #41, "Using the Dispose Design Pattern doesn't guarantee cleanup."



    .NET Gotachas
    .NET Gotachas
    ISBN: N/A
    EAN: N/A
    Year: 2005
    Pages: 126

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net