Why is the last MDI child form that has been closed not collecting garbage?

We had problems with memory leaks in our application. I was able to reproduce one of the problems with the following simple example:

Replication setup

1) Create the following helper class that will be used to track the creation / destruction of the object.

public class TestObject
{
    public static int Count { get; set; }

    public TestObject()
    {
        Count++;
    }

    ~TestObject()
    {
        Count--;
    }
}

2) Create an MDI form with three buttons, the first button will create a new MDI child as follows:

    private void ctlOpenMDI_Click(object sender, EventArgs e)
    {
        Form newForm = new Form();
        newForm.MdiParent = this;
        newForm.Tag = new TestObject();
        newForm.Show();
    }

The second button will be used the same way, but with a child form other than MDI:

    private void ctlOpenNonMDIForm_Click(object sender, EventArgs e)
    {
        Form newForm = new Form();
        newForm.Tag = new TestObject();
        newForm.Show();
    }

The third button will be used to collect garbage and then display how many instances of TestObject live:

    private void ctlCount_Click(object sender, EventArgs e)
    {
        GC.Collect();
        GC.WaitForPendingFinalizers();

        MessageBox.Show("Count: " + TestObject.Count);
    }

Replication steps

1) " MDI", MDI "". Count: 1. MDI , , - - .

:

MDI , 3 , . Count: 1. , MDI .

Counter-:

1) " -MDI", . . Count: 0, .

, :

        Form form = new Form();
        form.MdiParent = this;
        form.Show();
        form.Close();

. MDI, - ? ?

, , .

+3
2

, Form - "FormerlyActiveMdiChild". . , .

- . windbg Microsoft, Windows (http://www.microsoft.com/whdc/devtools/debugging/default.mspx) . , windbg, .

  • MDI Form TestChildForm, .
  • windbg. .NET !loadby sos mscorwks.
  • windbg !dumpheap -type TestChildForm.

     Address       MT     Size
    01e2e960 001c650c      320  
    
  • !gcroot 01e2e960.

    ESP:3de7fc:Root:01e29a78(System.EventHandler)->
    01e26504(WindowsFormsApplication1.Form1)->
    01e269b8(System.Windows.Forms.PropertyStore)->
    01e2ef04(System.Windows.Forms.PropertyStore+ObjectEntry[])
    
  • !dumparray -details 01e2ef04 01e2e960.

          MT    Field   Offset                 Type VT     Attr    Value Name
    6797ea24  40032a3       10         System.Int16  1 instance       56 Key
    6797ea24  40032a4       12         System.Int16  1 instance        1 Mask
    6798061c  40032a5        0        System.Object  0 instance 01e2e960 Value1
    
  • , !name2ee System.Windows.Forms.dll System.Windows.Forms.Form, !dumpclass 6604cb84 ( !name2ee) 56.

          MT    Field   Offset                 Type VT     Attr    Value Name
    67982c4c  4001e80      fd8         System.Int32  1   static       56 PropFormerlyActiveMdiChild
    

Visual Studio windbg, "", "", " ". .load sos .loadby sos mscorwks.

+2

, , , . , .

.

private void ctlOpenMDI_Click(object sender, EventArgs e)
{
    Form newForm = new Form();
    newForm.FormClosing += new FormClosingEventHandler(form_Closing);
    newForm.MdiParent = this;
    newForm.Tag = new TestObject();
    newForm.Show();
}

.

private void form_Closing(object sender, EventArgs e)
{
    Form form = sender as Form;
    form.MdiParent = null;
}

reset MdiParent, , MdiChild. , , reset.

-1

Source: https://habr.com/ru/post/1719410/


All Articles