I am not sure to evaluate what happens if I call the
GC.SuppressFina lize(this) for a object.
My question is:
In case I call GC.SuppressFina lize(this) from with in one of my
object, do I
then have to somehow - if yes how - release instances created in the
constructor manuelly?
Simplified example:
public class TestObject
{
private List<stringstrL ist;
public TestObject()
{
strList = new List<string>();
}
public void Dispose()
{
<releas my hw>
GC.GC.SuppressF inalize(this);
}
}
Would this code mean, that I have to "release" strList within my
dispose or will GC still take care of strList?
GC will still take care of strList. The only difference is that TestObject's
Finalize method won't be called. And, since TestObject doesn't actually override
the Object.Finalize method (using the destructor syntax), there's no need
to call GC.SuppressFina lize in the code that you posted. GC.SuppressFina lize(this)
will essentially do nothing in the code you posted.
Here's what happens when you override the Finalize method (or in C#, declare
a destructor). This will help explain the situation where calling GC.SuppressFina lize
is necessary.
When an object is allocated that overrides the Finalize method, a pointer
to the object is placed in a special 'finalization' queue. When the garbage
collector sees that the object can be reclaimed, it scans the finalization
queue and finds that a pointer to the object exists in the queue. The GC
then removes the pointer from the 'finalization' queue and adds it to the
'freachable' queue. The object actually survives the GC because the Finalize
method hasn't been called yet. There is a special thread in the runtime for
calling Finalize methods. When a pointer appears in the freachable queue,
this thread wakes up and calls the Finalize methods of the objects in the
queue. After this is done, the freachable queue is empty and the next GC
will reclaim the object (unless the object is resurrected in some way by
its Finalize method).
The net result of all of this is that, relying on the Finalize method can
have some unwanted side effects -- not the least of which is performance.
Enter the GC.SuppressFina lize method. When this is called, it ensures that
the Finalize method of the specified object is not called. So, the object
will be reclaimed on GC and not moved to the freachable queue. This makes
it particularly when implementing IDisposable.
FWIW, here is an abstract class that I use as a base IDisposable implementation:
public abstract class DisposableObjec t: IDisposable
{
private enum DisposeState { NotDisposed, Disposing, Disposed }
private DisposeState m_State = DisposeState.No tDisposed;
private object m_StateLock = new object();
~DisposableObje ct() // overrides Object.Finalize ()
{
InnerDispose(fa lse);
}
private void InnerDispose(bo ol disposing)
{
lock (m_StateLock)
{
if (m_State != DisposeState.No tDisposed)
return;
m_State = DisposeState.Di sposing;
try
{
Dispose(disposi ng);
}
finally
{
m_State = DisposeState.Di sposed;
}
}
}
protected abstract void Dispose(bool disposing);
public void Dispose()
{
InnerDispose(tr ue);
GC.SuppressFina lize(this); // Finalize method will no longer be called.
}
}
Note that this class ensures that two threads cannot cause the object to
be disposed more than once. When overridding the Dispose(bool disposing)
method, make sure to check the 'disposing' parameter. If this is true, it
is called on the same thread that Dispose() was called on. If it is false,
it is being called from the runtime's finalizer thread that calls Finalize
methods.
Best Regards,
Dustin Campbell
Developer Express Inc.