在对话框表单周围使用using语句以确保垃圾回收。

8
我们有一个包含数千个窗体的Windows Forms应用程序。
其中许多是通过ShowDialog()方法临时显示为对话框。
这个应用程序已经存在多年了,我们发现由于窗体或其使用的控件中的各种资源泄漏,许多窗体不能及时进行垃圾回收。
具体来说,我们发现GDI+资源的一些例子没有被正确地处理,尽管可能存在其他类型的尚未被表征的资源泄漏。
虽然解决这个问题的正确方法显然是遍历每个窗体和每个控件,并消除所有的资源问题。这需要一些时间来完成。
作为一个短期替代方案,我们发现显式调用Dispose()函数可以启动垃圾回收过程,窗体及其资源会立即被释放。
我的问题是,在每个窗体的ShowDialog()块中加入using语句并在窗体显示后调用Dispose()是否是一个合理的解决方法?这是否也是一个普遍适用的好做法?
例如,将现有代码更改为:
public void ShowMyForm()
{
    MyForm myForm = new MyForm();
    myForm.ShowDialog();
}

变为这样:

至此:

public void ShowMyForm()
{
    using (MyForm myForm = new MyForm())
    {
        myForm.ShowDialog();
    }
}

在我们的测试中,第一个例子中MyForm的Dispose()方法从未被调用,而在第二个例子中立即被调用。
在我们花时间追踪每个特定资源问题的同时,这是否是一种合理的短期解决方法?
我们是否可以考虑其他短期解决方法和/或确定和解决此类资源问题的方法?

是的,这是使用和丢弃对话框的最佳实践。此外,Dispose仅在显式调用它时(例如通过“using”)才会被调用,因此如果您有非托管资源,则可能需要实现终结器或使用包装类,如各种SafeHandle派生类,以确保即使未调用Dispose,也能清理资源。 - Dan Bryant
1
请注意Dispose()和GC之间存在巨大的区别。在这里,Dispose是正确的做法,它将释放非托管资源,但不是GC。 - Marc Gravell
旁注:使用 Controls.Clear(); 可能会导致内存泄漏。请参见汉斯在此处的评论 http://stackoverflow.com/a/7706549/939213 。 - ispiro
3个回答

14
根据MSDN,使用ShowDialog方法显示的窗体必须显式调用Dispose方法进行释放(而不像使用Show方法那样)。当以模态对话框的方式显示一个窗体时,点击关闭按钮(位于窗体右上角的带有X字样的按钮)会隐藏该窗体并将DialogResult属性设置为DialogResult.Cancel。与非模态窗体不同,.NET Framework不会在用户单击对话框的关闭窗体按钮或设置DialogResult属性的值时调用Close方法。相反,窗体被隐藏,并且可以再次显示而无需创建对话框的新实例。因为以对话框的方式显示的窗体是隐藏而不是关闭,所以在应用程序不再需要该窗体时,必须调用该窗体的Dispose方法进行释放。

这是非常有趣的学习内容,特别是因为它出现在Form.ShowDialog方法的帮助文本中:http://msdn.microsoft.com/en-us/library/c7ykbedk.aspx - Avalanchis
如果在ShowDialog之后没有调用Dispose,但是窗体中没有资源泄漏,那么它最终会被处理掉吗(在应用程序终止之前)? - Avalanchis

2

对于模态对话框,您应该使用以下模式:

using ( var dlg = new MyDialog() )
{
    // other code here to initialize, etc.
    dlg.ShowDialog();
}

由于MyDialog是从Form派生而来的,并且Form实现了IDisposable,因此这种模式将正确地清除您的对话框。

这不应该是一个“短期解决方案”,而是您应该调用所有模态对话框的标准方式。

非模态对话框则是另一回事。您需要自己跟踪它们,并在应用程序中适当的点调用Dispose


1
通常使用using语句来处理实现了IDisposable接口的对象是一个好方法。
举个小例子:
假设你有一个第三方“组件”。你不知道内部发生了什么,也许这个对象创建了一个临时文件并在Dispose时删除该文件。如果你不调用Dispose()并且不使用using语句,那么该文件将永远不会被删除。
在你的情况下,只要你打开你的窗体modal,你也可以这样做。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接