GOTCHA 35 Writing Finalize() is rarely a good idea


GOTCHA #35 Writing Finalize() is rarely a good idea

An object is said to be accessible if traversing from a reference on the stack will lead you to it, directly or indirectly. When an object becomes inaccessible, it is ready for garbage collection, since no part of your code needs to access its content. When it is actually removed is up to the garbage collector. If this object implements a Finalize() method, it is executed at the time of its cleanup by the CLR.

The state change an object undergoes during the cleanup phase is shown in Figure 5-1. It first goes from accessible (A) to inaccessible (I). While in this "zombie" state, it occupies memory, but you cannot execute any of its methods or access any of its fields or properties. (But sometimes it may look like you can. See Gotcha #36, "Releasing managed resources in Finalize( ) can wreak havoc." The object may remain in this inaccessible state anywhere from fractions of seconds to hours (or longer), depending on the garbage collector and the memory usage of the application. When the garbage collector eventually decides to clean the object up, it inspects it to see if the Finalize() method needs to be executed. If so, the object is brought to the resurrected state (R) and becomes accessible once again. Once the Finalize() method has run, the object goes to the Inaccessible-no-need-to-finalize state (IF). Then the memory occupied by the object is reclaimed and the object becomes non-existent (N).

Jeffrey Richter explains the CLR garbage-collection mechanism in great detail. Refer to "Garbage Collection" in the section "on the web" in the Appendix.

If the object does not have a Finalize() method, the cleanup will be faster. It can go from the inaccessible state (I) to the non-existent state (N) directly, as shown in Figure 5-1 by the dashed line labeled with a question mark.

Should you implement the Finalize() method? Consider Example 5-1.

Figure 5-1. States of an object during its cleanup phase


Example 5-1. Code with Finalize()

C# (Finalize)

 using System; namespace WhyNoFinalize {     public class SomeClass     {         private SomeOtherClass ref1;         public SomeClass(SomeOtherClass givenObject)         {             ref1 = givenObject;         }         ~SomeClass()         {             ref1 = null;         }     } } 

VB.NET (Finalize)

 Public Class SomeClass     Private ref1 As SomeOtherClass     Public Sub New(ByVal givenObject As SomeOtherClass)         ref1 = givenObject     End Sub     Protected Overrides Sub Finalize()         ref1 = Nothing         MyBase.Finalize()     End Sub End Class 

In this example, SomeClass holds a reference to an instance of SomeOtherClass. The Finalize() method of SomeClass sets the reference ref1 to null/Nothing. Is this necessary?

No, it isn't. Whenever an instance becomes inaccessible, so do all of the other objects that are accessible only through that instance. So, when an object of SomeClass becomes unreachable, the object of SomeOtherClass that ref1 refers to does also. Once a group of objects becomes inaccessible, all of them might be collected during the next garbage-collection sweep. There is no guarantee in which order their Finalize() methods will be called. So the object of SomeOtherClass that ref1 refers to may have already been removed by the time SomeClass.Finalize() is called! Setting ref1 to null/Nothing is redundant. But writing the Finalize() method provides code for the garbage collector to execute, and obliges it to resurrect the object, thus unnecessarily slowing it down. Even worse, the memory is not reclaimed until the next garbage-collection sweep, further delaying the cleanup.

IN A NUTSHELL

Do not write the Finalize() method unless you have a good reason. It makes more work for the garbage collector. The main reason for implementing Finalize() is to make sure you free unmanaged resources, as you'll see in Gotcha #36, "Releasing managed resources in Finalize( ) can wreak havoc." Only write it in the context of the Dispose design pattern (see Gotcha #40, "Implementing IDisposable isn't enough").

SEE ALSO

Gotcha #36, "Releasing managed resources in Finalize( ) can wreak havoc," Gotcha #37, "Rules to invoke base.Finalize( ) are not consistent," Gotcha #38, "Depending on Finalize() can tie up critical resources," Gotcha #39, "Using Finalize() on disposed objects is costly," 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