C# - ShowDialog(this)内存泄漏

时间:2013-12-31 00:11:57

标签: c# .net winforms memory-leaks

我有显示新表单对话框的示例代码:

private void button1_Click(object sender, EventArgs e)
{
    (new Form2()).ShowDialog(this);
    GC.Collect();
}

如果表单有按钮,面板标签等,则执行此form2的Dispose方法,但如果我添加toolStrip,则不执行Dispose方法。为什么在这些情况下执行Dispose?

如果表格是由ShowDialog显示的话我加了我应该执行Dispose方法,但是为什么它有时没有呢?

编辑: 可以在ShowDialog之后添加Collect方法。此方法仅用于测试并多次执行。

要检查是否执行了Dispose方法,我添加了断点(在调试模式下)。当然,程序结束时会执行使用ToolStrip的示例处理。

好的,我知道如何正确实现它,因为我感兴趣的是为什么GC无法清理,如果在表单上是toolStrip?

显示它的最简单的代码是: 例1 - 结果 - 100, 实施例2 - 结果> 0(GC可以清理), 例3 - 总是0。 为什么示例2和3有所不同?

private class Form2 : Form
    {
        public static int disposed = 0;    
        byte[] data;
        private System.Windows.Forms.ToolStrip toolStrip11;
        public Form2(bool addToolStrip)
        {
            data = new byte[100000];
            this.Shown += (sender, e) => { this.Close(); };
            this.Controls.Add(new Button());

            if (addToolStrip)
            {
                this.toolStrip11 = new System.Windows.Forms.ToolStrip();
                this.Controls.Add(this.toolStrip11);
            }
        }

        protected override void Dispose(bool disposing)
        {
            ++disposed;
            base.Dispose(disposing);
        }
    }
    private void ShowResult()
    {
        GC.Collect(); GC.Collect();
        GC.WaitForFullGCComplete();
        MessageBox.Show(Form2.disposed.ToString());
        Form2.disposed = 0;
    }

    private void button1_Click(object sender, EventArgs e)
    {
        //proper
        for (int i = 0; i < 100; ++i)
        {
            using(Form2 f = new Form2(true))
            {
                f.ShowDialog();
            }
        }
        ShowResult();
        //ok GC can clean - why yes ?
        for (int i = 0; i < 100; ++i)
        {
            Form2 f = new Form2(false);
            f.ShowDialog();
        }
        ShowResult();
        //GC can't clean - why not ?
        for (int i = 0; i < 100;a ++i)
        {
            Form2 f = new Form2(true);
            f.ShowDialog();
        }
        ShowResult();
    }

2 个答案:

答案 0 :(得分:1)

您的代码没有意义 - 在您声称泄漏内存的电话之前,您正在强制执行垃圾收集周期。

你应该只implement Dispose to get rid of unmanaged resources。对于托管资源,尝试在任何常见用例中击败垃圾收集器是没有意义的。此外,我不确定你是怎么认为你“泄漏内存”因为你无法预测或知道GC何时正常工作 - 严格来说.NET程序只有一个如果GC 拒绝正确清理内存泄漏。由于这是未向开发人员公开的信息 - 即使是明确的清理,也可以自行决定选择不收集所有潜在的垃圾 - 根据定义,您的索赔无法核实。

答案 1 :(得分:0)

许多一次性物品也有定型器。当GC通常清理对象时,它将首先检查它是否有一个尚未运行的终结器。如果没有,它会进入队列以运行终结器,然后实际符合垃圾回收的条件。

由于这种机制,一些一次性物体可能会清理其资源,即使它们没有明确处理。

那就是说,这是一种不可靠的机制。一旦对象有资格进行收集,您不知道何时收集该对象,并且在运行终结器时该对象所处的状态可能导致与“自身”的异常和未定义的交互。

您应尽可能避免依赖终结器,而应明确处置此类可支配资源。