我们的应用程序中存在内存泄漏问题。我已经设法通过以下简单示例复制了其中一个问题:
复制设置
1) 创建以下帮助类,用于跟踪对象的创建/销毁。
public class TestObject
{
public static int Count { get; set; }
public TestObject()
{
Count++;
}
~TestObject()
{
Count--;
}
}
2)创建一个包含三个按钮的MDI表单,第一个按钮将创建一个新的MDI子,如下所示:
private void ctlOpenMDI_Click(object sender, EventArgs e)
{
Form newForm = new Form();
newForm.MdiParent = this;
newForm.Tag = new TestObject();
newForm.Show();
}
第二个按钮将用于执行相同的操作,但使用的是非 MDI 子窗体:
private void ctlOpenNonMDIForm_Click(object sender, EventArgs e)
{
Form newForm = new Form();
newForm.Tag = new TestObject();
newForm.Show();
}
第三个按钮将用于垃圾收集,然后显示有多少 TestObject 实例处于活动状态:
private void ctlCount_Click(object sender, EventArgs e)
{
GC.Collect();
GC.WaitForPendingFinalizers();
MessageBox.Show("Count: " + TestObject.Count);
}
复制步骤
1) 点击 Open MDI form 按钮,然后关闭 MDI form,然后点击 count 按钮。它将返回 Count: 1. MDI 子窗体和它引用的对象没有被垃圾回收 - 某些东西必须仍然具有对它的引用。
还:
单击打开 MDI 窗体三次,关闭所有 3 个窗体,然后单击计数按钮。它将返回 Count: 1。似乎最后关闭的 MDI 子窗体没有被垃圾收集。
反例:
1)点击打开非MDI表单,关闭它。然后单击计数按钮。它将返回 Count: 0,表单和对象已被垃圾回收。
解决方法
我可以通过这样做来解决这个问题:
Form form = new Form();
form.MdiParent = this;
form.Show();
form.Close();
在垃圾收集之前。这使得这个虚拟表单成为最后一个关闭的 MDI 子表单,以便其他表单可以被垃圾收集 - 但为什么我必须这样做?到底是怎么回事?
它也有点难看,因为你会看到表单打开和关闭的闪烁,而且看起来也很hacky。