Suppose you build a class that needs a temporary directory for its
operations:
class MyClass
{
private string m_tempDir;
public MyClass()
{
m_tempDir = @"C:\" + System.Guid.NewGuid().ToString();
System.IO.Directory.CreateDirectory( m_tempDir );
}
}
When an object of this type is instantiated, a temporary directory will be
created. When the instance is garbage collected, I would like the directory
to disappear. I'ts very tempting to add a finalizer to the class:
~MyClass()
{
System.IO.Directory.Delete( m_tempDir );
}
***BUT*** as I understood, the order in which managed objects is
inpredictable so m_tempDir could be collected before the MyClass finalizer
code is executed. This makes it illegal to access m_tempDir in the
finalizer.
So the question is: which pattern can be used to guarantee that the
temporary directory will be deleted when a MyClass instance is collected?
I don't want to rely on the client code to call some dispose method, I want
the class itself to make sure it cleans up the temp directory. I also don't
like the idea of allocating some unmanaged memory to store the filename: in
my opinion, this does not result in .Net code as it is meant to be
written...
More generic: which pattern can be used if a finalizer needs to carry out
some clean-up actions (delete a file, stop a thread, stop sponsoring a
remote object,... ) that need access to other managed objects to which the
finalizing object holds the only reference?
David Browne - 21 Dec 2004 21:57 GMT
> Suppose you build a class that needs a temporary directory for its
> operations:
[quoted text clipped - 22 lines]
> inpredictable so m_tempDir could be collected before the MyClass finalizer
> code is executed.
No. You are confusing Finalization with Garbage Collection. Finalization
always occurs between garbage collections. One garbage collection will
identify finalizable objects and queue them for finalization. Then, after
they are finalized, a subsequent garbage collection will collect them.
All finalizable objects identified in a garbage collection are queued for
finalization. The finalizer thread then runs each finalizer. The order in
which the finalizers of are run is unpredictable, so you should not access
other finalizable objects in your finalizer.
Garbage collection for your finalizable object and for any object to which
your finalizable object has a reference is guaranteed not to happen until
after your finalizer runs, usually long, long after your finalizer has run.
Since your finalizer caused your object to survive GC, it has been promoted
and it will linger on the managed heap until the next collection of it's new
generation.
>This makes it illegal to access m_tempDir in the finalizer.
m_tempDir is fine because System.String does not have a finalizer. When
~MyClass runs, the MyClass instance and all objects it references (and all
objecects they reference, etc) are still allocated on the managed heap.
They have all been promoted, and will not be collected until the _next_
garbage collection of their new generation. If any other object in this
graph has a finalizer, that finalizer may run either before or after
~MyClass. If the finalizer on the referenced object has already run, it is
likely to be in an unusable state and may generate an exception or do
something unpredictable if you try invoking its methods from inside
~MyClass.
> So the question is: which pattern can be used to guarantee that the
> temporary directory will be deleted when a MyClass instance is collected?
>
> I don't want to rely on the client code to call some dispose method, I
> want the class itself to make sure it cleans up the temp directory.
In addition to the finalizer, you should implement the Disposable pattern.
Either just Dispose, or Dispose and a Finalizer: never just a finalizer.
Dispose should delete the directory, and then call GC.SupressFilalize(this).
This will prevent your finalizer from running _if_ the client remembers to
call dispose. The finalizer is then just a backup. You want to let Dispose
clean up your objects whenever possible since having a finalizer forces your
object and all the objects it references to be promoted to later generation
and disposed much later. This can significantly add to the memory
utilization of your application and cost you more time in garbage
collection.
David
Jon Skeet [C# MVP] - 21 Dec 2004 22:03 GMT
> Suppose you build a class that needs a temporary directory for its
> operations:
[quoted text clipped - 22 lines]
> code is executed. This makes it illegal to access m_tempDir in the
> finalizer.
No. The variable definitely can't be garbage collected - but it may
have been finalized. If you know that string doesn't have a finalizer
(I don't know either way, to be honest) then you can use it.
> So the question is: which pattern can be used to guarantee that the
> temporary directory will be deleted when a MyClass instance is collected?
[quoted text clipped - 4 lines]
> my opinion, this does not result in .Net code as it is meant to be
> written...
Be aware that the finalizer may not be run, in certain situations.

Signature
Jon Skeet - <skeet@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too