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

在winforms中检测gdi/用户处理程序泄漏,winforms,controls,memory-leaks,profiling,Winforms,Controls,Memory Leaks,Profiling,我做了很好的winforms 2.0应用程序,它工作得很好,客户仍然很高兴,但不幸的是,我无法解决一个问题。问题是,在使用应用程序几个小时后,gdi用户处理的数量不断增加,最终进程无法分配更多对象,应用程序崩溃 我没有做任何花哨的事情,它是一个普通的应用程序,一些表单,一些更多的模式表单,一些DataGridView和很多TableLayoutPanel,我在其中添加了很多标签和文本框 我的问题是: 是否有“推荐做法” 关于添加/删除常规系统 运行时窗体上的控件(dgv/tlp) 如何检测系统

我做了很好的winforms 2.0应用程序,它工作得很好,客户仍然很高兴,但不幸的是,我无法解决一个问题。问题是,在使用应用程序几个小时后,gdi用户处理的数量不断增加,最终进程无法分配更多对象,应用程序崩溃

我没有做任何花哨的事情,它是一个普通的应用程序,一些表单,一些更多的模式表单,一些DataGridView和很多TableLayoutPanel,我在其中添加了很多标签和文本框

我的问题是:

  • 是否有“推荐做法” 关于添加/删除常规系统 运行时窗体上的控件(dgv/tlp)
  • 如何检测系统句柄的 泄漏-最好使用目视检查 studio和一种免费插件 (剖析器?)

检测图形和窗把手泄漏非常困难。至于在运行时查找它们的特定策略,我不能提出任何建议(尽管我很想听听其他人的建议!)

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

  • 虽然
    控件
    类的终结器将调用
    Dispose()
    ,但这是不确定的。不能保证垃圾收集器会最终确定任何对象。很可能会,但这不是保证
  • 与上述情况一致,表格是一个例外。当
    表单
    以非模式方式显示时(意思是通过
    Show()
    ,而不是
    ShowDialog()
    ),则当
    表单
    关闭时,它将确定地调用
    Dispose()
    。通过
    ShowDialog()
    显示的表单必须手动调用
    Dispose()
    ,才能确定地清理控制手柄
  • 记住这两件事,您可以做的最重要的事情是确保始终对显式创建的任何实现
    IDisposable
    的对象调用
    Dispose()
    。这包括
    Form
    s、
    Control
    s、
    Graphics
    对象,甚至像
    Pen
    Brush
    这样的图形助手类。所有这些类都实现了
    IDisposable
    ,一旦您不再需要它们,所有这些类都需要被处理掉
  • 尝试缓存图形实用程序类,假设您正在使用一些。虽然
    画笔
    创建起来相当轻巧,但它们确实占用了手柄,需要在完成后处理掉。与其一直创建它们,不如创建一个缓存管理器,允许您传入将在这些对象的构造函数中使用的参数,并保留该对象。具有相同参数的重复调用仍应仅使用一个实例。然后,您可以定期刷新缓存,或者在应用程序中的特定位置刷新缓存(如果您知道这些位置的话)

遵循这些指导原则将大大减少(如果不是消除的话)您的句柄泄漏。

我发现使用任务管理器和GDI对象列可见对于查找此类泄漏至关重要。您可以在调用前中断,记录GDI对象,然后在可疑调用后中断,以确定对象是否被正确释放,从而锁定特定区域。

以下是两个有用的GDI泄漏跟踪工具的源代码:


我已经成功地在很多VisualStudioC++项目中使用了它。我不确定我是否也使用.NET。

是的,我使用taskmanager检测到了问题,问这个问题的原因是如何帮助解决问题。在这种情况下,我认为Adam Robinson的帖子应该可以帮助您解决问题。谢谢您的建议。你能给我推荐一些工具/VS插件来帮助跟踪/检测源代码泄漏吗?@tomo,同样,不,我不知道有任何这样的工具。有一次我看了很多东西,因为我遇到了和你们面临的问题类似的问题。解决这些问题让我找到了上面的提示。作为MDI应用程序一部分的表单还需要手动调用Dispose():关闭时不释放表单的两个条件是:(1)它是多文档界面(MDI)应用程序的一部分,并且表单不可见;(2)您已经使用ShowDialog显示了表单。在这种情况下,您需要手动调用Dispose来标记窗体的所有控件以进行垃圾收集。@Eric:您能指出此控件上的权威链接吗?我在MSDN上没有看到任何关于这种行为的参考,我也不熟悉它。ShowDialog是正确的(正如我在回答中提到的),但我似乎找不到MDI行为的确认。