我们的应用程序中存在内存泄漏问题。我已成功通过以下简单示例复制了其中一个问题:
复制设置
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) 单击“打开 MDI 窗体”按钮,然后关闭 MDI 窗体,然后单击“计数”按钮。它将返回 Count: 1。 MDI 子窗体及其引用的对象没有被垃圾回收 - 某些东西仍然必须具有对它的引用。
Also:
单击打开 MDI 窗体三次,关闭所有 3 个窗体,然后单击计数按钮。它将返回 Count: 1。看起来最后关闭的 MDI 子窗体没有被垃圾回收。
反例:
1) 单击“打开非MDI 窗体”,将其关闭。然后单击计数按钮。它将返回Count:0,表单和对象已被垃圾收集。
解决方法
我可以通过这样做来解决这个问题:
Form form = new Form();
form.MdiParent = this;
form.Show();
form.Close();
在垃圾收集之前。这使得这个虚拟表单成为最后一个关闭的 MDI 子表单,以便其他表单可以被垃圾收集 - 但为什么我必须这样做呢?到底是怎么回事?
而且它有点难看,因为你会看到表单打开和关闭时闪烁,而且看起来也很老套。