We know that .NET has 2 super types. The Value-Type and Reference-Type. As I understand it, after I set all the roots of an Ref-Type object to null, the Ref-Type object is logically deleted from the stack, but remains in existence on the manged-heap. If the Ref-Type object uses some native resources, such as an opened-file, do I have to release these resources before or after I setting all the roots to null? And why?
You should not release the unmanaged resources directly unless you create you own unmanaged resource wrapper. Usually you call Dispose or Close to free the unmanaged resource. This is done to provide some control on how resources are reclaimed. If you use some class that wraps an unmanaged resource and provide some finalizer the Garbage Collector will reclaim the resource when the Finalizer Queue thread is handling the object. See Jeffrey Richter's article for more information
If you have an object that is using native resources, then you must make sure that object implements IDisposable
interface. You can then call MyObject.Dispose() and in that Dispose() method, make sure you're cleaning up your native resources.
Simply setting the object to NULL
is not enough since the native resource will hang around in memory.
If a reference type has native resources, whether directly or indirectly, it should implement IDisposable
. You should call Dispose
when you've finished using the object (assuming you "own" the resource), preferably with a using
statement:
using (Foo foo = new Foo(...))
{
...
} // Dispose called here
The Dispose
method should release all the resources.
If the type has direct references to unmanaged resources - usually via an IntPtr
- then it should have a finalizer. However, .NET 2.0 made this a lot simpler with SafeHandle
which can be used instead of IntPtr
. The advent of SafeHandle
basically means that very very few types should have a finalizer these days.
There are a few things that need to be clarified in your assumptions in order to give you an answer.
For most intents and purposes, .NET only has one "super" type, and that is System.Object.
(For the record there are some types in the type system that do not derive from System.Object)
System.ValueType inherits from System.Object.
Once you release all of the references to an object, then the object becomes eligible for garbage collection. It does not get deleted when the last reference is released. At some indeterminate point in the future, the memory that the object was stored in on the managed heap will be reclaimed by a garbage collection.
If the instance does in fact use some sort of native resources, then it should implement the IDisposable interface.
If this interface is implemented on the class your object is an instance of, then you should call the Dispose method, as a "proper" implementation of IDisposable would release any unmanaged resources (such as file handles, as you mention) at the time that Dispose is called.
If the Dispose method is not called on a class instance that implements IDisposable, and it is a "proper" implementation of that interface, then when the object is finalized, the unmanaged resources will be cleaned up.
However, just because a "proper" implementation of IDisposable will guarantee that unmanaged resources will be disposed of at some point in the future, it doesn't mean that one should not call Dispose. The presence of the IDisposable interface indicates that you should call Dispose as-soon-as-possible.
If you allocate native resources yourself (not via other means of the .NET-Framework), you have to release them before you are garbage-collected. This can/should be done by using a "Finalizer", i.e. ~MyClass()
which must NOT be confused with a destructor in C++.
Finalizers make GC slow, because they are executed on a separate thread and therefore require two GC cylces to get rid of an object.
Therefore you should also implement IDisposable
where you free your native resources and call GC.SuppressFinalize(this)
.