检测 winforms 中的 gdi / 用户处理程序泄漏

Posted

技术标签:

【中文标题】检测 winforms 中的 gdi / 用户处理程序泄漏【英文标题】:detecting gdi / user handler leaks in winforms 【发布时间】:2009-05-05 21:26:00 【问题描述】:

我做了很好的 winforms 2.0 应用程序,它运行良好,客户仍然很高兴,但不幸的是我无法解决一个问题。问题是,在使用应用程序几个小时后,gdi 用户句柄数不断上升,最终进程无法分配更多对象,应用程序崩溃......

我没有做任何花哨的事情,它是常规应用程序、一些表单、更多模态表单、一些数据网格视图和许多表格布局面板,我在其中添加了许多标签和文本框。

我的问题是:

是否有任何“推荐实践” 关于添加/删除常规系统 运行时表单控件 (dgv/tlp) 如何检测系统句柄' 泄漏 - 最好使用视觉 工作室和一种免费插件 (分析器?)

【问题讨论】:

【参考方案1】:

检测图形和窗口句柄泄漏非常困难。至于在运行时找到它们的特定策略,我无法提出任何建议(尽管我很想听听别人的!)。

至于预防,这里有几点提醒:

虽然Control 类的终结器将调用Dispose(),但这是不确定的。您不能保证任何对象都会被垃圾收集器最终确定。很有可能会,但这不是保证。 按照上述规定,Forms 是一个例外。当Form 以非模态方式显示时(意味着通过Show(),而不是ShowDialog()),那么当Form 关闭时,它将确定性地调用Dispose()。通过ShowDialog() 显示的表单必须手动调用Dispose() 才能确定性地清理控制句柄。 牢记这两点,您可以做的最重要的事情是确保始终对您明确创建的任何实现IDisposable 的对象调用Dispose()。这包括 Forms、Controls、Graphics 对象,甚至像 PenBrush 这样的图形助手类。所有这些类都实现了IDisposable,一旦您不再需要它们,就需要将它们全部丢弃。 尝试缓存图形实用程序类,假设您正在使用一些。虽然 PenBrush 的创建相当轻巧,但它们确实占用了句柄,并且需要在完成后处理掉。与其一直创建它们,不如创建一个缓存管理器,它允许您传入将在构造函数中为这些对象使用的参数并保留该对象。使用相同参数的重复调用仍应仅使用一个实例。然后,您可以定期或在应用程序中的特定位置刷新缓存(如果您知道缓存在哪里)。

遵循这些准则将大大减少(如果不能消除)您的手柄泄漏。

【讨论】:

感谢您的建议。你能推荐我任何可以帮助跟踪/检测源代码泄漏的工具/VS 插件吗? @tomo,同样,不,我不知道有任何此类工具。有一次我做了很多研究,因为我遇到了与您所面临的问题类似的问题。解决它们是我得到上述提示的原因。 作为 MDI 应用程序一部分的表单也需要手动调用 Dispose():关闭时未处理表单的两个条件是 (1) 它是多文档的一部分界面(MDI)应用程序,并且表单不可见; (2) 您已经使用 ShowDialog 显示了表单。在这些情况下,您需要手动调用 Dispose 以将表单的所有控件标记为垃圾回收。 @Eric:你能指出一个权威的链接吗?我在 MSDN 上没有看到对这种行为的任何引用,我也不熟悉它。 ShowDialog 是正确的(正如我在回答中提到的那样),但我似乎找不到 MDI 行为的确认。【参考方案2】:

我发现使用具有可见 GDI 对象列的任务管理器对于查找此类泄漏至关重要。您可以通过在调用前中断来定位特定区域,记下 GDI 对象,然后在可疑调用之后中断以确定对象是否被正确释放。

【讨论】:

是的,我使用任务管理器检测到了这个问题,问这个问题的原因是如何帮助解决它。 在这种情况下,我认为 Adam Robinson 的帖子应该可以帮助您解决问题。【参考方案3】:

两个有用的 GDI 泄漏跟踪工具的源代码可以在这里找到:link text

我已在许多 Visual Studio C++ 项目中成功使用它。我不确定我是否也使用 .NET。

【讨论】:

以上是关于检测 winforms 中的 gdi / 用户处理程序泄漏的主要内容,如果未能解决你的问题,请参考以下文章

GDI 图形对象上的鼠标 OnDrag 事件

防止 WPF 中的内存泄漏

C# WinForms - 任何人都知道 C# GDI 库不是 SLOW GDI+

如何解决 winforms 错误“GDI+ 中发生一般错误。”?

使用 GDI+ 显示像素数据

GDI+ DrawImage 在 C++ (Win32) 中比在 C# (WinForms) 中慢得多