After all the answers, I created a small program that shows what Jodrell wrote (thanks to Jodreka!)
- An object can be garbage collected as soon as it is not used, even if I have a link to it
- This will be done if not debugging.
I wrote a simple class that allocates unmanaged memory and a MemoryStream. The latter implements System.IDisposable.
For all of StackOverflow, I have to implement System.IDisposable and free up unmanaged memory, and also Dispose a managed memoryStream if my Dispose is called, but if my finalizer is called, I have to free unmanaged memory.
I am writing several 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 many times, ao here in stackoverflow in the Proper Use of the IDisposable Interface
by the way: for simplicity, I excluded exception handling
A simple console program creates an object, does not use it, but saves a link 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 the variable a contains a reference to the object until the end of the procedure. I forgot to Dispose, so my finalizer must take care of the disposal
Call this method from the main one. Run the release from the debugger and run it using the command line.
- If you start from the debugger, the object remains valid until the end of the procedure, so until the garbage collector finishes collecting
- If you run from the command line, then the object is completed before the procedure is completed, although I still have a reference to the object.
So Jodrell is right:
Unmanaged code requires Dispose () and Finalize, use Dispose (bool)
Managed disposable objects need Dispose (), preferably through Dispose (bool). In Dispose (bool), only Dispose () of managed objects is called, if the utility
they don’t trust the debugger: it finishes work on objects at different points in time than without a debugger