Why does my destructor never run?

24,835

Solution 1

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.

Solution 2

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.

Solution 3

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.

Solution 4

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.

Solution 5

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.

Share:
24,835
Jeson Martajaya
Author by

Jeson Martajaya

Updated on April 04, 2020

Comments

  • Jeson Martajaya
    Jeson Martajaya about 4 years

    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:

    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 garbage collector?

    Is there another way to know whether Form1 has been garbage collected ?

  • apacay
    apacay over 12 years
    @agent-j shouldn't that be "Form1.Dispose " + (disposing ? "disposing " : "")
  • slfan
    slfan over 12 years
    IDisposable is not automatically predictable, you have to call Dispose or use using(). And how would you call Dispose()?
  • David Heffernan
    David Heffernan over 12 years
    @slfan What are you talking about? Dispose runs when it is called, invariably via using. Where did I say that Dispose would run automatically?
  • agent-j
    agent-j over 12 years
    @slfan, my point is that this is called by the finalizer only if necessary. If someone disposes the form explicitly, the destructor (finilize method) likely never is executed because of GC.SupressFinalize. See the Dispose pattern for more info.
  • slfan
    slfan over 12 years
    @agent-j: You're right, I haven't seen that Dispose() with the bool parameter is actually implemented in the Form class. Therefore your Dispose will be called from the finalizer or from the base method. But you should ALWAYS call base.Dispose(disposing); when you override this method.
  • slfan
    slfan over 12 years
    You wrote "if you need predictable disposal...". If you don't use using or call it explicitly, it's not called. As I have never used using with a form, it's even less predictable than the finalizer.
  • David Heffernan
    David Heffernan over 12 years
    @slfan IDisposable exists to provide predictable disposal. What else is it for?! Should you so desire to implement it on a form, and use using, then the Dispose method would run at a predictable point. I didn't say it was a good idea to do that. What I did say was "If you implement IDisposable, and dispose of your object, then the code in Dispose will run".
  • LoganS
    LoganS over 12 years
    @slfan - I don't think he meant it that way.
  • Jeson Martajaya
    Jeson Martajaya over 12 years
    I understand what you mean: 1) It is impossible to have a predictable destructor. 2) It is possible to have predictable IDisposable with using. More in blog.dmbcllc.com/2008/11/10/dispose-with-using
  • David Heffernan
    David Heffernan over 12 years
    as @slfan says, IDisposable is not typically used on a form.
  • slfan
    slfan over 12 years
    Ok, try my 2nd guess. Maybe you have some references to the form.
  • slfan
    slfan over 12 years
    Yes, and it does NOT call the finalizer either! That's why I would not call it a predictable disposal. It's just a standard pattern to work with unmanaged resources and any class that has a finalizer should implement the IDisposable pattern. But in my opinion this answer is not a reply to the question above.
  • David Heffernan
    David Heffernan over 12 years
    @slfan I even say in the answer that the finalizer won't run.
  • gmail user
    gmail user over 10 years
    I tried the 2nd option and it worked. I think yours is most closest answer compares to others.
  • Hi-Angel
    Hi-Angel over 9 years
    Hm… I am wonder, are destructors in C# have a mean at all? Usually it is used to free some resources, close file descriptors (e.g. I am tried to close socket here), but since here no a hint about the time the destructor called, it is impossible to use it as usual.
  • Thick_propheT
    Thick_propheT about 9 years
    For one, Forms already implement IDisposable. Secondly, if the Form is the main Form for the app, just wrap it in a using statement in Program.cs.