.NET Tutorials, Forums, Interview Questions And Answers
Welcome :Guest
 
Sign In
Register
 
Win Surprise Gifts!!!
Congratulations!!!


Top 5 Contributors of the Month
david stephan

Home >> Articles >> C# >> Post New Resource Bookmark and Share   

 Subscribe to Articles

.NET Memory Management and Finalization

Posted By:Gautam Kanaujia       Posted Date: December 31, 2010    Points: 75    Category: C#    URL: http://www.dotnetspark.com  

This article demonstrate how garbage collector works.
 

.NET Memory Management and Finalization

Finalization and Resurrection

As you may have noticed in the previous section, objects become reachable again when they're placed in the ReadyToFinalize queue. This is sometimes called "resurrection," since the objects seem to come back to life from being dead. (Of course, then they are supposed to die again, but why not enjoy life for 50 milliseconds more?)

But you, as a developer, have the power to bring objects back to life for considerably longer. To do that, just make the object reachable from your application code. Here is an example:

public class MyFinalizableObject {

  public MyFinalizableObject() {

  }

  public override void Finalize() {

    // Assign pointer to this object to static data member in MyApplication

    MyApplication.somePointer = this;

  }

}...

 

public class MyApplication {

  static public Object somePointer;           // Defaults to null

  ...

}

Inside the Finalize() code, the MyFinalizableObject type saves a reference to itself into a static data member in the MyApplication class during finalization. Saving a reference makes the object undergoing finalization reachable again, and the garbage collector will not consider it collectable. However, resurrecting an object brings unwanted consequences. When it's being finalized, the object is no longer part of the RegisteredForFinalization queue; it has been removed from the queue by Finalizer thread. That means this object will never be finalized again. Your class should contain logic to allow the cleanup of the resources used by the type in some other place.

 

There are very few good uses of resurrection. The best approach is to avoid it whenever possible. However, if resurrection is absolutely necessary, you may use a method called ReRegisterForFinalize, which takes a single parameter - the pointer to the object - and puts that object back in the RegisteredForFinalization queue. Doing so ensures that the Finalize() method is run again when the object is garbage collected. If you call ReRegisterForFinalize multiple times, the Finalize() method ends up being called a corresponding number of times. That's probably not the result you would expect from finalization.

 

Finalization and Weak References

Going back to the garbage collection basics, when a root points to an object, that object is considered reachable and cannot be garbage collected. .NET has special kind of references, called weak references, which allow an object to be garbage collected when still referenced, and at the same time allow an application to access the object before it is actually garbage collected. The process of accessing the object via weak reference is slightly different from accessing the object via plain reference. Let's consider what happens when an object is referenced via a weak reference.

Assume the only reference to an object is a weak reference. The garbage collection engine decides to perform the collection and encounters that object. The object is considered not reachable (that's why the reference is called "weak") ,and is garbage collected. Later, an application tries to access that same object via weak reference and fails, because the object no longer exists.

On the other hand, let's assume the application tries to access the same object via weak reference before garbage collection is run. To access the object via weak reference, your application has to obtain a strong reference to the object first. But, as soon as the strong reference to object is obtained, the object is no longer collectable, because it just became reachable through that strong reference. When the application is done with using that object, the strong reference is destroyed, but the weak reference still exists. Now, if the garbage collector decides to collect that object, it may very well do so.

A good question would be: why do we need that type of reference? In certain memory-tight conditions (or in your own virtual memory implementation) you may choose to keep the objects (currently not being used) around only if the environment you are running in can afford to do so. If the environment decides to do a garbage collection, it may collect objects not currently in use; later, our application will try to access them and, in case of failure, can create that same objects again and de-serialize them from some kind of persistent storage.

The WeakReference type offers two constructors:

WeakReference(Object target);

WeakReference(Object target, Boolean trackResurrection);

The target parameter identifies the object to which this reference points; the trackResurrection parameter indicates if WeakReference should continue tracking the object after the Finalizer thread has called the Finalize() method for that object. Most of the time, tracking objects after the Finalize() method is called is not needed, so the first constructor is used.

Most of the time, when a weak reference to an object is created, the strong reference to the same object is set to null. That allows garbage collection to collect that object if needed. If a strong reference to an object still exists, garbage collection won't be able to collect that object, and having a weak reference to the same object does not make a lot of sense. So, as soon as a weak reference is created, get rid of the strong reference pointing to the same object.

Dispose and Garbage Collection

As we all know by now, garbage collection is non-deterministic, and there is no guarantee as to when a particular object will be garbage collected and the Finalize() method will be called. Yet, you want to dispose of resources you no longer need as soon as possible, to reduce the strain on the system. For instance, as soon as you have retrieved your data from a database connection, the connection should be closed. Not closing the connection immediately after use results in eating up system resources you do not really need. .NET provides the IDisposable interface and the Dispose() method for resource cleanup.

 

The main difference between Dispose and Finalize() is that Finalize() is protected and can not be called explicitly; Dispose() can be called explicitly. Calling Dispose() on an object accomplishs two things: it cleans up any resources that were allocated by the object, and it marks the object so that the garbage collection does not call its Finalize() method when this object is being garbage collected. Finalize() is not called, because all resources has already been cleaned up by Dispose(). By calling Dispose(), we save the overhead of a call to Finalize() (by removing the object from RegisteredForFinalization queue), and perform resources cleanup at the most appropriate time. However, keep in mind that Dispose() can be called more than once (for example, from different threads), so you need to make sure you don't perform resource cleanup more than once. Here is an example:

 

public class MyDisposableClass : IDisposable {

  bool done;   // indicate if object is already disposed

  public MyDisposableClass() {

    done = false;

  }

 

  public ~MyDisposableClass() {

    Dispose(true);

  }

 

  public void Dispose(bool done) {

    if (!done) {

      GC.SuppressFinalize(this);

      // TODO: perform resource cleanup here

      done = true;

    }

  }

}

To ensure that resources are released only once, make sure you always call GC.SuppressFinalize() in the Dispose method so that Finalize does not get called later in the process.


 Subscribe to Articles

     

Further Readings:

Responses
Author: shishir         Company URL: http://www.dotnetspark.com
Posted Date: January 03, 2011

Awesome thanks for the post....

Post Comment

You must Sign In To post reply

    Read also another Resources from the same Author

Find More Articles on C#, ASP.Net, Vb.Net, SQL Server and more Here

Hall of Fame    Twitter   Terms of Service    Privacy Policy    Contact Us    Archives   Tell A Friend