I am not sure to evaluate what happens if I call the
GC.SuppressFinalize(this) for a object.
My question is:
In case I call GC.SuppressFinalize(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<string> strList;
public TestObject()
{
strList = new List<string>();
}
public void Dispose()
{
<releas my hw>
GC.GC.SuppressFinalize(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.SuppressFinalize in the code that you posted. GC.SuppressFinalize(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.SuppressFinalize
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.SuppressFinalize 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 DisposableObject: IDisposable
{
private enum DisposeState { NotDisposed, Disposing, Disposed }
private DisposeState m_State = DisposeState.NotDisposed;
private object m_StateLock = new object();
~DisposableObject() // overrides Object.Finalize()
{
InnerDispose(false);
}
private void InnerDispose(bool disposing)
{
lock (m_StateLock)
{
if (m_State != DisposeState.NotDisposed)
return;
m_State = DisposeState.Disposing;
try
{
Dispose(disposing);
}
finally
{
m_State = DisposeState.Disposed;
}
}
}
protected abstract void Dispose(bool disposing);
public void Dispose()
{
InnerDispose(true);
GC.SuppressFinalize(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