GDI处理DotNET应用程序

.net memory-leaks count gdi handle

4353 观看

7回复

3113 作者的声誉

我的纯DotNET库在非托管桌面应用程序中作为插件运行。我一直在获得一个稳定的(虽然很低)崩溃报告流,似乎表明GDI句柄有问题(错误消息中的字体等恢复到系统字体,各种控件的显示中断,大规模崩溃后不久)。

我的表单几乎没有控件,但我在用户控件中做了很多GDI +绘图。什么是告诉我正在使用多少手柄甚至泄漏的好方法?

谢谢,大卫

作者: David Rutten 的来源 发布者: 2010 年 3 月 20 日

回应 (7)


1

807152 作者的声誉

从TaskMgr.exe,Processes选项卡中很容易看到。查看+选择列,勾选GDI对象。

您的描述确实与手柄泄漏相匹配。这不应该在托管程序中真正发生,终结器应该照顾你忘记调用Dispose()。除非你不消耗大量垃圾收集堆空间。它也可能是非托管应用程序泄漏句柄,它们经常这样做。

作者: Hans Passant 发布者: 20.03.2010 12:45

3

9840 作者的声誉

除了性能监视器,您还可以尝试使用旧的任务管理器。

检查Process选项卡,然后单击View> Select Columns...并检查GDI对象。

作者: Paulo Santos 发布者: 20.03.2010 12:46

1

102886 作者的声誉

如果您还没有这样做,请确保在您正在使用的任何GDI +绘图对象上调用IDisposable.Dispose。您通常会使用C#using构造执行此操作,例如:

using(Brush brush = ...)
{
    ...
}

静态代码分析工具(如FxCop或Visual Studio的Team System版本中内置的版本)可以帮助检测无法调用Dispose的情况。

未能以这种方式调用Dispose是一种潜在的句柄泄漏,因为在垃圾收集器看起来合适之前不会回收句柄。

作者: Joe 发布者: 20.03.2010 12:47

2

39088 作者的声誉

决定

我过去不得不处理同样的问题。为了检查应用程序分配的GDI对象数量,可以使用名为GDIUsage的免费工具。

在我的情况下,应用程序崩溃,因为它分配了超过10.000个GDI对象,这是Windows XP中的一个硬限制。可能值得研究一下。

我在这里写了关于这个问题的博客:http
//megakemp.com/2009/02/25/gdi-memory-leak-in-windows-forms/

作者: Enrico Campidoglio 发布者: 20.03.2010 12:49

3

84872 作者的声誉

看看GDIView(它是免费软件):

GDIView是一个独特的工具,可显示每个进程打开的GDI句柄列表(画笔,笔,字体,位图等)。它显示每种类型的GDI句柄的总计数,以及每个句柄的详细信息。此工具对于需要跟踪其软件中的GDI资源泄漏的开发人员非常有用。

替代文字
(来源:nirsoft.net

请注意,默认情况下禁用自动刷新,但可以针对特定时间间隔启用和配置自动刷新:Options -> Auto Refresh -> Every [N] seconds

作者: Ray Vega 发布者: 07.04.2010 12:45

1

84872 作者的声誉

GDIObj是冯远提供的免费实用程序,作为他的书,Windows Graphics Programming:Win32 GDI和DirectDraw的示例程序可能很有用。

与任务管理器不同,它提供了不同GDI句柄类型的进一步细分计数,包括DC,区域,位图,调色板,字体,画笔等。

(但是,它只提供计数信息,而GDIView提供了有关句柄的更多细节。)

作者: Ray Vega 发布者: 07.08.2010 07:51

5

1244 作者的声誉

从Ray Vega的回答中的GDIView开始,我发现了这个提示

[DllImport("User32")] 
extern public static int GetGuiResources(IntPtr hProcess, int uiFlags);

  public static void GetGuiResourcesGDICount()      
  { 
      //Return the count of GDI objects.          
      Console.WriteLine("GDICount"+GetGuiResources(System.Diagnostics.Process.GetCurrentProcess().Handle, 0));      
  }

  private void button1_Click(object sender, System.EventArgs e)
  {
      GetGuiResourcesGDICount();
  }

GDIView通知说,这是被泄露的字体对象; 然后,我将调用添加GetGuiResources到我们的日志代码中,以检测在何时触发对象创建。

在我们的例子中,Label当父控件UserControl隐藏在后台窗口中时,我们会更新控件的文本。这会导致GDI泄漏字体句柄。为了解决这个问题,我们将逻辑更改为不更新,Label除非它当前在屏幕上可见。为了确定它是否可见,我们记录UserControl上次绘制的时间。

作者: user326608 发布者: 03.03.2012 03:32
32x32