【问题标题】:Memory leak in ShowDialog even after disposing itShowDialog中的内存泄漏,即使在处理后也是如此
【发布时间】:2013-08-08 07:12:58
【问题描述】:

我创建了一个示例 Windows 窗体应用程序,其中包含两个窗体 - form1 和 form2。

Form1 包含一个按钮,单击时我将 form2 显示为一个对话框,如下所示。

private void button1_Click(object sender, EventArgs e)
        {
            Form2 form2 = new Form2();
            try
            {
                form2.ShowDialog();
            }
            catch (Exception ex)
            {

            }
            finally
            {
                if (form2 != null)
                {
                    form2.Dispose();
                    form2 = null;
                }
            }   

        }

然后我检查了应用程序,例如单击按钮,然后它将打开 form2,关闭它。并持续了大约 6 次。

当我使用 DevPartner 检查应用程序时,它始终显示 Form2 form2 = new Form2(); 已泄露

当我在网上查看时,它说如果我们使用 ShowDialog,我们需要在关闭表单后处理表单,即为什么我尝试在 finally 块中处理。但它仍然显示该行泄漏。 任何人都可以就这次泄漏提出您的建议。

【问题讨论】:

  • 我总是在使用显示对话框的表单周围使用 using 块,您尝试过吗?
  • 我通常不做那种处理表单的方式。为什么不尝试将 Dispose 代码放在 form2 中的按钮中?
  • @Sayse:是的,最初我尝试过使用..但没有运气..
  • @JackFrost:在 form2 的按钮中处理代码。?抱歉没找到你?
  • 您确定泄漏不会在一段时间后消失吗?可能只是 gc 还没有清理它。您可以尝试添加 GC.Collect 但绝对不要将其保留在您的代码中

标签: c# winforms memory-leaks devpartner


【解决方案1】:

通常,当您使用 IDisposable 对象时,您应该在 using 语句 中声明和实例化它。 using 语句 以正确的方式调用对象的 Dispose 方法,并且一旦调用 Dispose,它也会导致对象本身超出范围。在 using 块中,对象是只读的,不能修改或重新分配。

using 语句可确保调用 Dispose,即使在您调用对象上的方法时发生异常也是如此。

【讨论】:

    【解决方案2】:

    您应该调查您的 Form2 以找到任何对外部事件和根引用的 subsctioptions。 所有这些都应在表单处置时删除。

    在以下代码中,泄漏的原因是订阅了 Idle 事件。在 Dispose 方法中删除订阅以避免泄漏。

    Form2()
    {
        Application.Idle += Application_Idle;
    }
    
    void Application_Idle(object sender, EventArgs e)
    {   
    }   
    
    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            Application.Idle -= Application_Idle;
        }
    }
    

    【讨论】:

    • 告诉我一种将其添加到评论中的方法
    • 对不起,是的,我已经修复了答案的第一部分以防止丢失上下文
    • 没有表单是空的,表单中没有控件和订阅。
    【解决方案3】:

    这可能是你工具的检查规则,因为实例的创建不在try-catch之内。

    试试这样:

    private void button1_Click(object sender, EventArgs e) {
        Form2 form2;
        try {
            form2 = new Form2();
            form2.ShowDialog();
        } finally {
            if (form2 != null) {
                form2.Dispose();
                form2 = null;
            }
        }
    }
    

    甚至更简单:

    private void button1_Click(object sender, EventArgs e) {
        using (var form2 = new Form2()) {
            form2.ShowDialog();
        }
    }
    

    【讨论】:

    • 我的代码和你的第一个示例有什么区别吗?即使我们在 try 块之外实例化 form2,我认为它也会在最终块中处理。
    • 是的,但是如果你的 Form2 在构造函数中抛出异常,那么它就不会被释放。这就是您的工具所抱怨的。
    • 好的。正如我所说的 form2 不包含任何控件。
    • 我可以尝试在form2的dispose方法中调用GC.Collect()吗?这是编码的好方法吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-06
    • 1970-01-01
    • 2015-03-04
    相关资源
    最近更新 更多