Disposing my System.IDisposable object in my finalizer - c#

There are several discussions here on StackOverflow about what to do if my object manages other managed objects that implement System.IDisposable.
Note: Below I am not talking about unmanaged code. I fully understand the importance of cleaning up unmanaged code
Most of the discussions say that if your object owns another managed object that implements System.IDisposable, then you should also implement System.IDisposable, in which case you should call the Dispose() of the disposable objects your object holds. This would be logical, because you don't know whether the disposable object you own uses unmanaged code. You only know that the creator of the other object thought it would be wise if you'd call Dispose as soon as you don't need the object anymore.
A very good explanation of the Disposable pattern was given here on StackOverflow, edited by the community wiki:
Proper use of the IDisposable interface
Quite often, and also in the mentioned link I read:
"You don't know the order in which two objects are destroyed. It is entirely possible that in your Dispose() code, the managed object you're trying to get rid of is no longer there."
This baffles me, because I thought that as long as any object holds a reference to object X, then object X will not and cannot be finalized.
Or in other words: as long as my object holds a reference to object X I can be certain that object X is not finalized.
If this is true, then why could it be, that if I hold the reference to my object until my finalize, the object I refer to is already finalized?

The truth is somewhere between the two:
The object can't be garbage collected, so the possibility of the object no longer "being there" isn't true
An object can be finalized when there are no longer any references to it from other non-finalizable objects.
If object X refers to object Y, but both are finalizable, then it's entirely possible for object Y to be finalized before object X, or even for them to be finalized concurrently.
If your assumption were correct, then you could create two objects which refer to each other (and have finalizers), and they could never be garbage collected because they could never be finalized.

Quoting Eric Lippert's, When everything you know is wrong, part two
Myth: Keeping a reference to an object in a variable prevents the
finalizer from running while the variable is alive; a local variable
is always alive at least until control leaves the block in which the
local was declared.
{
Foo foo = new Foo();
Blah(foo); // Last read of foo
Bar();
// We require that foo not be finalized before Bar();
// Since foo is in scope until the end of the block,
// it will not be finalized until this point, right?
}
The C# specification states that the runtime is permitted broad latitude to
detect when storage containing a reference is never going to be accessed
again, and to stop treating that storage as a root of the garbage collector.
For example, suppose we have a local variable foo and a reference is written
into it at the top of the block. If the jitter knows that a particular read is
the last read of that variable, the variable can legally be removed from the
set of GC roots immediately; it doesn’t have to wait until control leaves the
scope of the variable. If that variable contained the last reference then the
GC can detect that the object is unreachable and put it on the finalizer queue
immediately. Use GC.KeepAlive to avoid this.
Why does the jitter have this latitude? Suppose the local variable is
enregistered into the register needed to pass the value to Blah(). If foo
is in a register that Bar() needs to use, there’s no point in saving the
value of the never-to-be-read-again foo on the stack before Bar() is
called. (If the actual details of the code generated by the jitter is of
interest to you, see Raymond Chen’s deeper analysis of this issue.)
Extra bonus fun: the runtime uses less aggressive code generation and
less aggressive garbage collection when running the program in the
debugger, because it is a bad debugging experience to have objects
that you are debugging suddenly disappear even though the variable
referring to the object is in scope. That means that if you have a bug
where an object is being finalized too early, you probably cannot
reproduce that bug in the debugger!
See the last point in this article for an even more horrid version of
this problem.

If done properly, you don't have to worry about disposing objects that are already disposed. Every implementation of Dispose should just not do anything if it had been disposed before.
So indeed, you cannot know whether any child objects have been disposed or finalized already (because the order of finalization is random, see other post), but you can safely call their Dispose method anyway.

In most cases when Finalize is called on an object which holds references to one or more IDisposable objects, one or more of the following will apply:
The other object has already been cleaned up, in which case calling Dispose is at best useless.
The other object has been scheduled to be finalized as soon as possible, but hasn't yet, in which case calling Dispose is probably unnecessary.
The other object's cleanup code cannot be used safely within the finalizer threading context, in which case calling Dispose could likely be disastrous.
The other object is still being used by code elsewhere, in which case calling Dispose could likely be disastrous.
There are a few situations where code knows enough about IDisposable objects that it's dealing with to know either that none of the above apply, or that it should trigger cleanup despite the above; those situations, however, may be better served by having the other objects supply a method other than Dispose which the object being finalized can call.

After all the answers, I created a small program that shows what Jodrell wrote (thank you Jodrell!)
An object can be garbage collected as soon as it will not be used, even if I have a reference to it
This will only be done if not debugging.
I wrote a simple class that allocates unmanaged memory and a MemoryStream. The latter one implements System.IDisposable.
According to everyone on StackOverflow I should implement System.IDisposable and free the unmanaged memory as well as Dispose the managed memoryStream if my Dispose is called, but if my finalizer is called I should only free the unmanaged memory.
I write some diagnostic console messages
class ClassA : System.IDisposable
{
IntPtr memPtr = Marshal.AllocHGlobal(1024);
Stream memStream = new MemoryStream(1024);
public ClassA()
{
Console.WriteLine("Construct Class A");
}
~ClassA()
{
Console.WriteLine("Finalize Class A");
this.Dispose(false);
}
public void Dispose()
{
Console.WriteLine("Dispose()");
this.Dispose(true);
GC.SuppressFinalize(this);
}
public void Dispose(bool disposing)
{
Console.WriteLine("Dispose({0})", disposing.ToString());
if (!this.IsDisposed)
{
if (disposing)
{
Console.WriteLine("Dispose managed objects");
memStream.Dispose();
}
Console.WriteLine("Dispose unmanaged objects");
Marshal.FreeHGlobal(memPtr);
}
}
public bool IsDisposed { get { return this.memPtr == null; } }
}
This program follows the Dispose Pattern as described numerous times, a.o. here in stackoverflow in Proper use of the IDisposable interface
by the way: for simplicity I've left out exception handling
A simple console program creates the object, doesn't use it, but keeps the reference to it and forces the garbage collector to collect:
private static void TestFinalize()
{
ClassA a = new ClassA() { X = 4 };
Console.WriteLine("Start Garbage Collector");
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine("Done");
}
Note that variable a holds a reference to the object until the end of the procedure. I forget to Dispose, so my finalizer should take care of disposing
Call this method from your main. Run the (release) build from the debugger and run it via a command prompt.
If run from the debugger then the object stays alive until the end of the procedure, so until after the garbage collector has finished collecting
If run from a command prompt, then the object is finalized before the procedure ends, even though I still have a reference to the object.
So Jodrell is right:
unmanaged code needs Dispose() and Finalize, use Dispose(bool)
Managed disposable objects need Dispose(), preferably via Dispose(bool). In Dispose(bool) only call Dispose() of managed objects if disposing
don't trust the debugger: it makes that objects are finalized on different moments than without debugger

Related

When finalize is invoked on an object with other objects, is the order is not guaranteed?

Trying to understand how an object is reclaimed. Read here that the order of objects being reclaimed is not guaranteed.
For example, my class has the following code -
class MyClass: IDisposable
{
private List<string> _fileNames;
// some other code and methods here with constructor
~MyClass()
{
Dispose(false);
}
private void Dispose(bool dispose)
{
foreach (string file in _fileNames)
{
// log something with dispose
File.Delete(file);
}
}
}
Does it mean that when the GC tries to reclaim this object, there is no guarantee that the _fileNames is still populated with strings and not null? Or, can one still use the list of strings above to free up resources? In the link posted, it mentions -
'The finalizers of two objects are not guaranteed to run in any specific order, even if one object refers to the other. That is, if Object A has a reference to Object B and both have finalizers, Object B might have already been finalized when the finalizer of Object A starts.'
So does it mean that the list may no longer be useful in the Dispose (assuming dispose is false)?
If the method call comes from a finalizer, only the code that frees
unmanaged resources should execute. The implementer is responsible for
ensuring that the false path doesn't interact with managed objects
that may have been disposed. This is important because the order in
which the garbage collector disposes managed objects during
finalization is non-deterministic.
Implementing Dispose
But it's moot because you shouldn't implement finalizers. Pretty much ever.
Consider your example. If someone fails to call Dispose, your object will eventually become unreachable, and eventually GC will figure that out and try to run your finalizer. However it's not guaranteed to ever run, and it's not guaranteed to run in any particular timeframe. It could be hours.
So what is really gained by adding the finalizer? Not much.
Failing to call Dispose on an IDisposable is a bug. So the only time the finalizer will run is when there's a bug. So it might be a good idea to have a finalizer that just throws an exception, crashing your program, so you can find and fix the whatever didn't call Dispose(). But having a finalizer try to clean up after buggy code is usually a bad idea.

Confused. CA1063 is wrong? GC.SuppressFinalize(this)

I have a simple class MyDataClass with a member (obj) that implements IDisposable:
public class MyDataClass : IDisposable
{
private DisposableObject obj;
private List<string> list;
private int c;
public MyDataClass()
{
obj = new DisposableObject();
list = new List<string>();
c = 114;
}
public void Dispose()
{
obj.Dispose();
}
}
public class DisposableObject : IDisposable
{
public void Dispose()
{
// Free resource
Console.WriteLine("Dispose DisposableObject");
}
}
When I run the Code Analysis I get the CA1063 warning which shows me that I should call GC.SuppressFinalize() method in the Dispose() method in MyDataClass implementation.
And I am really confused about this CA1063 warning. Because as far as I know, I should call GC.SuppressFinalize() to indicate to the garbage collector:
"Hey GC, do not worry about this object because I have done already all cleaning work for you!"
So please confirm if I am wrong or not. If I will add the GC.SuppressFinalize() I will get rid of the CA1063 but it will cause that GC will not clean my object. So I will have a memory leak because other class members (managed code) will be not cleaned.
The method GC.SuppressFinalize() indicates to the VM not to run the finalizer. That's the funny looking method in C#:
~MyDataClass()
To remove the warning, you need to either seal your class, or implement the complete IDisposable pattern.
I have the feeling that you are still confused, despite having accepted an answer. Let me explain:
The Garbage Collector (GC) has the unenviable task to remove any objects from memory that are not reachable.
Reachability
An object A is only reachable when there is any chain of references from any GC root to the object. Examples of roots are the stack, and any static fields. So, to determine whether A is reachable, all the GC has to do is to find a reference on the stack that refers to an object that has a reference that refers to an object ... that refers to object A. If it cannot find such a chain, object A is not reachable.1
So, once the GC has determined that A is not reachable, it will want to remove it from memory.
However, before it does that, the GC checks whether A has a finalizer (~A) that must be run. If not, it removes A from memory and the GC is done with it.
Finalization
However, if A has a finalizer that must be run, it cannot remove the object from memory before the finalizer is finished. So, it adds a reference to A to the finalizer queue and does not remove the object from memory (yet). Now the Garbage Collector is done with A for now. However, when the GC runs again, it will again try to determine whether A is reachable. Luckily, the finalizer queue is also one of the Garbage Collector's roots, so it determines that there is a reference from the finalizer queue to A, therefore A is reachable and will again not be removed from memory.
Along comes the finalizer thread, a thread that periodically checks whether there are any objects in the finalizer queue. If there are, it picks one and runs its finalizer method. Eventually, the finalizer thread will run the finalizer of A. Once this is done, the reference to A is removed from the finalizer queue.
Clean up
Then, some time later, the Garbage Collector runs again, and tries to determine again whether A is reachable. As it is now not referenced anywhere, not even from the finalizer queue, A is not reachable. The GC removes A from memory.
You see, normally the GC can remove unreachable objects in the same collection cycle it detects them, but when an object has a finalizer that needs to be run, it can take multiple cycles for the object to be collected. Therefore CA1063 recommends you to put GC.SuppressFinalize() in the Dispose method to let the GC know that the objects does not need to be finalized before it is removed from memory. So, the object is always2 removed from memory eventually.
Note that when you don't have a finalizer you don't have to add GC.SuppressFinalize(), so in that respect the CA1063 warning is a bit superfluous.
More in-depth information about the Garbage Collector can be found in this MSDN article.
1) Reachability is the reason why it is common to set references to null after disposing them. This makes the referenced object most likely unreachable, and therefore a candidate to be removed.
2) It is possible (but certainly not recommended) to resurrect A by using the finalizer to add a reference to A from another reachable object or root (e.g. a static field). This makes A reachable again, and the Garbage Collector will not remove it. However, its finalizer will not run again, as it has already been invoked once.
If I will add the GC.SuppressFinalize() I will get rid of the CA1063
but it will cause that GC will not clean my object.
No, your objects will still be collected.
"Hey GC, do not worry about this object because I have done already all cleaning work for you!"
You're actually only saying: don't worry about the Finalizer (destructor) of this object. If it has one.
And that is where Code Analysis is getting it wrong: your class does have an IDisposable.Dispose() method but it does not have a destructor. So the warning is pointless, being over protective and triggering on the wrong reason. Disable or ignore it.

Anything wrong with spamming GC.KeepAlive(KeyboardHookPointer)?

GC.KeepAlive()
References the specified object, which makes it ineligible for garbage collection from the start of the current routine to the point where this method is called.
Not really sure about what GC.KeepAlive does other than simply store a reference so the Garbage Collector doesn't collect the object. But does calling GC.KeepAlive() on an object permanently keep an object from being collected? Or do you have to re-call GC.KeepAlive() every so often (and if so, how often)? I want to keep my keyboard hook alive.
When you compile .NET code for Release target, the garbage collector is really aggressive, that is, it has the potential to be.
Take this example:
public void Test()
{
FileStream stream = new FileStream(....);
stream.Write(...);
SomeOtherMethod();
}
In this example, once the call to Stream.Write has returned, this method has no more use for the stream variable, and is thus considered out of scope, which means that the FileStream object is now eligible for collection. If the garbage collector runs during the call to SomeOtherMethod that stream object might get collected.
Edit: As #Greg Beech points out in the comments, an object can be collected even if an instance method is currently executing on it.
For instance, let's say the code in FileStream.Write looks like this:
public void Write(byte[] buffer, ...)
{
IntPtr unmanagedHandle = _InternalHandleField;
SomeWindowsDll.WriteBuffer(unmanagedHandle, ...);
...
here, the method first grabs the internal field containing an unmanaged handle. The object will not be collected before this has happened. But, if this is the last field of the object, or the last instance-method of the object, being accessed in Write, before transitioning over to just P/Invoke calls, then the object is now eligible for collection.
And since FileStream probably has a unmanaged file handle (I say probably, I don't know), it probably has a finalizer as well, so the unmanaged file handle is in risk of being closed before the call to WriteBuffer has completed. That is, if the supposed implementation of .Write is as above, which it most likely isn't.
If you wish to prevent this, make the stream object live for the duration of the call to SomeOtherMethod for whatever reason, you need to insert code after the call that "uses" the object in some way. If you don't want to call a method or read a property on the object, you can use the artificial "usage" method of GC.KeepAlive to do it:
public void Test()
{
FileStream stream = new FileStream(....);
stream.Write(...);
SomeOtherMethod();
GC.KeepAlive(stream);
}
The method does nothing, but it has been flagged with attributes so that it won't be optimized away. This means that the stream variable is now in use for the duration of the call to SomeOtherMethod and the FileStream object stored in it will not get collected during that time.
That's all it does. GC.KeepAlive leaves no permanent mark on anything, it does not alter the lifetime of the object after being called, it simply adds code that "uses" the variable at some point, which prevents the garbage collector from collecting the object.
I learned about this method, or rather, the point of this method, the hard way with some code that looked like this:
public void Test()
{
SomeObjectThatCanBeDisposed d = new SomeObjectThatCanBeDisposed();
SomeInternalObjectThatWillBeDisposed i = d.InternalObject();
CallSomeMethod(i);
}
Notice that I construct an instance of an object implementing IDisposable, and in the original case, it also implemented a finalizer. I then "fished" out an object it kept track of, and the way the disposable object was set up (incorrectly) was that once the finalizer ran, it would also dispose of internal objects (which is bad). In the above code, d becomes eligible for collection once the internal object has been extracted, and once the object is collected, it finalizes itself by disposing of the object I extracted. This means that during the call to CallSomeMethod, the object passed to the method died and I couldn't understand why.
Of course, the fix for the above code was not to use GC.KeepAlive, but instead to fix the incorrect finalizer, but if the "internal object" had been an unmanaged resource, things might've been different.
Now, as for your keyboard hook, if you store your reference in a root, like a static field, a member field of an object that is also kept alive, etc. then it should not be collected out of the blue.
GC.KeepAlive (as well as GC.Collect) shouldn't be used in production code, because it doesn't solve any problems, it just creates more race conditions. They're only useful for diagnosing a problem.
If you have a managed object being used by native code so the garbage collector can't see it is still being used, you should be using GCHandle.Alloc.
EDIT: Some supporting evidence:
http://msdn.microsoft.com/en-us/library/ms182293(VS.100).aspx
http://blogs.msdn.com/ddietric/archive/2007/09/23/a-good-reason-for-calling-gc-collect.aspx
http://blogs.msdn.com/johan/archive/2007/04/20/memory-management-in-the-net-framework.aspx
http://blogs.msdn.com/clyon/archive/2006/08/28/728688.aspx
http://blogs.msdn.com/cbrumme/archive/2003/04/19/51365.aspx
GC.KeepAlive isn't good for very much, and it's definitely only good when the usage by native code is guaranteed to end before returning, which isn't the case for a keyboard hook.

Setting an object to null vs Dispose()

I am fascinated by the way the CLR and GC works (I'm working on expanding my knowledge on this by reading CLR via C#, Jon Skeet's books/posts, and more).
Anyway, what is the difference between saying:
MyClass myclass = new MyClass();
myclass = null;
Or, by making MyClass implement IDisposable and a destructor and calling Dispose()?
Also, if I have a code block with a using statement (eg below), if I step through the code and exit the using block, is the object disposed of then or when a garbage collection occurs? What would happen if I call Dispose() in the using block anyay?
using (MyDisposableObj mydispobj = new MyDisposableObj())
{
}
Stream classes (eg BinaryWriter) have a Finalize method? Why would I want to use that?
It's important to separate disposal from garbage collection. They are completely separate things, with one point in common which I'll come to in a minute.
Dispose, garbage collection and finalization
When you write a using statement, it's simply syntactic sugar for a try/finally block so that Dispose is called even if the code in the body of the using statement throws an exception. It doesn't mean that the object is garbage collected at the end of the block.
Disposal is about unmanaged resources (non-memory resources). These could be UI handles, network connections, file handles etc. These are limited resources, so you generally want to release them as soon as you can. You should implement IDisposable whenever your type "owns" an unmanaged resource, either directly (usually via an IntPtr) or indirectly (e.g. via a Stream, a SqlConnection etc).
Garbage collection itself is only about memory - with one little twist. The garbage collector is able to find objects which can no longer be referenced, and free them. It doesn't look for garbage all the time though - only when it detects that it needs to (e.g. if one "generation" of the heap runs out of memory).
The twist is finalization. The garbage collector keeps a list of objects which are no longer reachable, but which have a finalizer (written as ~Foo() in C#, somewhat confusingly - they're nothing like C++ destructors). It runs the finalizers on these objects, just in case they need to do extra cleanup before their memory is freed.
Finalizers are almost always used to clean up resources in the case where the user of the type has forgotten to dispose of it in an orderly manner. So if you open a FileStream but forget to call Dispose or Close, the finalizer will eventually release the underlying file handle for you. In a well-written program, finalizers should almost never fire in my opinion.
Setting a variable to null
One small point on setting a variable to null - this is almost never required for the sake of garbage collection. You might sometimes want to do it if it's a member variable, although in my experience it's rare for "part" of an object to no longer be needed. When it's a local variable, the JIT is usually smart enough (in release mode) to know when you're not going to use a reference again. For example:
StringBuilder sb = new StringBuilder();
sb.Append("Foo");
string x = sb.ToString();
// The string and StringBuilder are already eligible
// for garbage collection here!
int y = 10;
DoSomething(y);
// These aren't helping at all!
x = null;
sb = null;
// Assume that x and sb aren't used here
The one time where it may be worth setting a local variable to null is when you're in a loop, and some branches of the loop need to use the variable but you know you've reached a point at which you don't. For example:
SomeObject foo = new SomeObject();
for (int i=0; i < 100000; i++)
{
if (i == 5)
{
foo.DoSomething();
// We're not going to need it again, but the JIT
// wouldn't spot that
foo = null;
}
else
{
// Some other code
}
}
Implementing IDisposable/finalizers
So, should your own types implement finalizers? Almost certainly not. If you only indirectly hold unmanaged resources (e.g. you've got a FileStream as a member variable) then adding your own finalizer won't help: the stream will almost certainly be eligible for garbage collection when your object is, so you can just rely on FileStream having a finalizer (if necessary - it may refer to something else, etc). If you want to hold an unmanaged resource "nearly" directly, SafeHandle is your friend - it takes a bit of time to get going with, but it means you'll almost never need to write a finalizer again. You should usually only need a finalizer if you have a really direct handle on a resource (an IntPtr) and you should look to move to SafeHandle as soon as you can. (There are two links there - read both, ideally.)
Joe Duffy has a very long set of guidelines around finalizers and IDisposable (co-written with lots of smart folk) which are worth reading. It's worth being aware that if you seal your classes, it makes life a lot easier: the pattern of overriding Dispose to call a new virtual Dispose(bool) method etc is only relevant when your class is designed for inheritance.
This has been a bit of a ramble, but please ask for clarification where you'd like some :)
When you dispose an object, the resources are freed. When you assign null to a variable, you're just changing a reference.
myclass = null;
After you execute this, the object myclass was referring to still exists, and will continue to until the GC gets around to cleaning it up. If Dispose is explicitly called, or it's in a using block, any resources will be freed as soon as possible.
The two operations don't have much to do with each others.
When you set a reference to null, it simply does that. It doesn't in itself affect the class that was referenced at all.
Your variable simply no longer points to the object it used to, but the object itself is unchanged.
When you call Dispose(), it's a method call on the object itself. Whatever the Dispose method does, is now done on the object. But this doesn't affect your reference to the object.
The only area of overlap is that when there are no more references to an object, it will eventually get garbage collected. And if the class implements the IDisposable interface, then Dispose() will be called on the object before it gets garbage collected.
But that won't happen immediately after you set your reference to null, for two reasons.
First, other references may exist, so it won't get garbage collected at all yet, and second, even if that was the last reference, so it is now ready to be garbage collected, nothing will happen until the garbage collector decides to delete the object.
Calling Dispose() on an object doesn't "kill" the object in any way. It is commonly used to clean up so that the object can be safely deleted afterwards, but ultimately, there is nothing magical about Dispose, it's just a class method.

is it legal to recreate a rooted reference to 'this' in a .net destructor?

Is it legal to write the following in .net ?
public class A
{
public int i = 0;
~A()
{
Aref = this;
}
}
public static A Aref;
static void Main(string[] args)
{
Aref = new A();
int gen = GC.GetGeneration(Aref);
Aref = null;
GC.Collect(gen, GCCollectionMode.Forced);
GC.WaitForPendingFinalizers();
Console.WriteLine(Aref.i);
Console.ReadLine();
}
It works and writes '0' to the console as expected, but I'm wondering if it's guaranteed to always work.
Does someone know what's happening behind the scene?
It's called resurrection, and it's legal. Google for ".net object resurrection" (and terms like it) and you'll find stuff like:
Resurrection and the .NET Garbage collector
Object Resurrection
Just make sure these zombie objects don't come back and try to eat your brain or something. Like all necromancy, this is dangerous stuff. (Mostly because the finalizers higher up in the class hierarchy can have released some essential resource. Also note that the finalizer won't be run a second time if the object gets "unreferenced", unless you call GC.ReRegisterForFinalize.)
It works because the first garbage collection doesn't collect the instance. It just schedules the instance to have its finalizer run. The finalizer then creates a new root to the instance, so when the next collection happens the instance is actually rooted and thus not up for collection.
You should be very careful with this tough. If the finalizer is used to make sure an object is disposed, this actually violates the protocol because the disposable patterns says that a disposed instance should throw an ObjectDisposedException if it is used after being disposed.
The garbage collector divides objects into three groups:Those which are still alive, because at last check a rooted reference existed outside the finalization queue;Those which need to be deleted, because no rooted reference exists anywhere;Those which need to be finalized, because a rooted reference exists in the finalization queue, but nowhere else.
Objects cannot be deleted unless there's no rooted reference anywhere. Finalization is a distinct stage before deletion; note that while an object is registered for finalization, all objects it references directly or indirectly will be protected from deletion, but not from finalization.

Categories

Resources