views:

57

answers:

5

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?

A: 

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

Ikaso
A: 

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.

Jason Evans
+3  A: 

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.

Jon Skeet
A: 

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.

casperOne
Can I rely on the GC to call the finalize method as a "safe-catch", and then the finalize will call my Dispose() method, instead of calling the Dispose method myself?
smwikipedia
@smwikipedia: Yes, you can, but you shouldn't treat IDisposable implementations this way. However, you have to implement the IDisposable interface properly (with a proper finalizer), as indicated by the link in the answer for the phrase '"proper" implementation of IDisposable' - http://msdn.microsoft.com/en-us/library/b1yfkh5e%28VS.71%29.aspx - **You should always call Dispose on an IDisposable implementation when you are done with it.**
casperOne
+1  A: 

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).

Martin C.