Collection, disposal and finalization
Today's post is written just to highlight the difference between three different concepts of how objects are managed in a .NET application.
First, let's start with the most basic: garbage collection. The MSDN topic on garbage collection fundamentals goes into quite a bit of detail and provides some great information. In a nutshell, what happens is that every so often, the system looks for objects that cannot possibly be used anymore because there are no more usable references to them, and reclaims the memory for them so it can be used to hold other objects or to return it to the operating system. It's the equivalent of a call to free in C, except that the system handles this for you.
Next, let's talk about finalization. This is simply the capability of objects to have a special method (caller finalizer) that is run when the garbage collector has decided that the object is ready to be collected. Under the covers, the garbage collector builds a queue of these objects and then calls them, possibly from a different thread at a later time.
This is used for cases like the following: let's say I have a class that uses P/Invoke to call into a Win32 API to open a file, and I store the handle in a field. If I don't close the file handle at some point, other applications may not be able to use the file. To make sure that at some point the file gets closed, I can write a finalizer for my object to do this.
There's still a problem with this, though. Garbage collection isn't constantly running for performance reasons, and we have no idea for how long we may be holding this file handle open. The convention in this case is to have our class implement the Dispose method of the IDisposable interface, and close the handle there. The users of the class need to remember to call this method when they want the resources released. In fact, C# even building the functionality of the using keyword around this method. But again, this is just convention - the .NET garbage collection only knows about whether objects can be reached or not and whether they need to be finalized.
Classes that implement IDisposable may also implement a finalizer, but this isn't always the case. Typically you only implement the finalizer if you own some resource that needs to be released, but you can always implement IDisposable to "propagate out" the object disposals.
Hopefully this explains some of the differences in a simple way. If you're thinking of implementing IDisposable on an object or of adding a finalizer, the Implementing Finalize and Dispose to Clean Up Unmanaged Resources topic on MSDN goes into more detail and more practical guidelines on how to do this. Very much worth reading.
Enjoy!
Comments
Anonymous
June 29, 2010
Why does it past a false into the Dispose(bool disposing) method from the finalizer whereby it doesn't free up the managed resources (only unmanaged)? Is it only there for performance so that it doesn't have to do extra work since if it's being called by the finalizer we don't have to worry about nulling out managed resources since the GC has determined the object and thereby it's properties aren't reachable anymore? Or should we disregard that and just clear up managed resources regardless of whether Dispose() is called explicitly via using, in the code, or via the finalizer? Thanks!Anonymous
June 29, 2010
@reno: yep, you're right. If you are disposing while the garbage collector is running, changing the references doesn't do you any good; they are already either marked for collection or someone else is keeping them alive anyhow. I'm no expert on the GC internals, but from reading msdn.microsoft.com/.../ms973837.aspx, I believe that making extra updates on older generation objects (which in a finalizer-called case will never be gen-0) will create additional work for the collector, as now it needs to see which object pointers from that area of memory need to be checked for liveness.