Why does my destructor never run?
I have a blank Winform with a destructor method
public partial class Form1 : Form
{
public Form1()
{
System.Diagnostics.Trace.WriteLine("Form1.Initialize " + this.GetHashCode().ToString());
InitializeComponent();
}
~Form1()
{
System.Diagnostics.Trace.WriteLine("Form1.Dispose " + this.GetHashCode().ToString());
}
}
When the form is destroyed, I want it to write to the output window:
(Form1 opened) Form1.Initialize 41149443 (Form1 closed) Form1.Dispose 41149443
MSDN suggests 3 ways in implementing destructor:
~Destructor() http://msdn.microsoft.com/en-us/library/66x5fx1b.aspx
IDisposable http://msdn.microsoft.com/en-us/library/system.idisposable.aspx
SafeHandle pattern http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.safehandle.aspx
However, none of these ways write "Form1.Dispose 41149443" to the output Window. Therefore, I am not able to tell whether the form has been destroyed or not. Suggestions ?
Should I give up hope on achieving this due to uncertainty of garbag开发者_运维问答e collector? Is there another way to know whether Form1 has been garbage collected ?Only one of the three ways to implement a destructor that you list actually involves a destructor, and that's ~Destructor()
.
If you implement IDisposable
, and dispose of your object, then the code in Dispose
will run, but there's no reason to think that your destructor will.
I think you chasing the impossible here. Destructors run as and when the garbage collector so decrees. It's not something that you have any control over. The GC is well within its rights to form the opinion that running destructors simply wastes time, and if there is plenty of memory it will form that opinion.
If you need predictable disposal, finalization etc., then use IDisposable
.
Unless you are studying garbage collection, a destructor is not the place for your tracing. You should look at Dispose (which is overridable in Form). This occurs after the unmanaged resource (like your window handle) has been released.
protected override void Dispose(bool disposing)
{
System.Diagnostics.Trace.WriteLine(
"Form1.Dispose " + (disposing ? "disposing " : "")
+ this.GetHashCode().ToString());
base.Dispose (disposing);
}
If you want to see if a form/control has been disposed, use the Control.IsDisposed
property.
Edit: Because of GC.SuppressFinalize
, your Finalize method (destructor syntax in C#) will never execute if Dispose is called explicitly (or by the framework).
For more information, see Implementing a Dispose Method.
Add a FormClosed event to the designer.
ie:
this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(Form1_FormClosed);
Then create the appropriate function to handle the event.
Yes, you should probably give up on the idea of a destructor, because they're non-deterministic by nature. I'm not sure why you need to have the form disposed as opposed to just closed, but simply closing it should be enough in most cases.
You could use IDisposable
but that depends on why you need the form to be garbage collected. If you need to re-use it, just create another instance.
The Form gets garbage collected when no references exist and the garbage collector happens to run. You can force the garbage collector by calling GC.Collect(). You should not reference any other object within a Finalizer (aka destructor) because the object might have been garbage collected already.
You can use memory analyzer tools to find out whether your object is garbage collected or not, if you really need to.
You also have to keep in mind that the finalizer is called from a thread other than the main thread.
EDIT: If your problem is just that you don't see the trace output, you might have to turn autoflush on
<configuration>
<system.diagnostics>
<trace autoflush="true" />
</system.diagnostics>
</configuration>
EDIT 2: There might be an external reference to your form, such as a registered event handler. I would suggest that you add a button in an administration area of your application which executes the following code:
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
Like this the garbage collector must run and should destroy your form (set a breakpoint into the finalizer). If not, you have some reference to the object which has to be destroyed.
You could try wrapping your form in a WeakReference object then check its IsAlive property to determine if it has been garbage collected. But, yes...as per the other answers you may be better off leaving it and trusting the GC to do its job!
精彩评论