首页 文章

C# - ShowDialog(this)内存泄漏

提问于
浏览
-3

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

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

    你的代码没有意义 - 在你声称泄漏内存的电话之前,你正在强制进行垃圾收集循环 .

    你应该只implement Dispose to get rid of unmanaged resources . 对于托管资源,它根本不确定你甚至不认为你是"leaking memory",因为你无法预测或知道GC何时正常工作 - 严格来说,如果GC refuses ,.NET程序只有真正的内存泄漏正确地清理它 . 由于这是未公开给开发商的信息 - 即使是明确的清理,也可以自行决定选择不收集所有可能的垃圾 - 根据定义,您的索赔无法核实 .

  • 1

    许多一次性物品也有定型器 . 当一个对象通常被GC清理时,它将首先检查它是否有一个没有't been run. If it hasn'的终结器,它进入队列以便运行终结器,然后实际上有资格进行垃圾收集 .

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

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

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

相关问题