6

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

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

谢谢,大卫

4

7 回答 7

5

从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上次绘制的时间。

于 2012-03-03T03:32:18.980 回答
4

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

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

替代文字
(来源:nirsoft.net

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

于 2010-04-07T00:45:15.343 回答
3

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

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

于 2010-03-20T12:46:19.563 回答
2

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

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

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

于 2010-03-20T12:49:01.093 回答
1

从 TaskMgr.exe 的“进程”选项卡中很容易看到。查看 + 选择列,勾选 GDI 对象。

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

于 2010-03-20T12:45:48.097 回答
1

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

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

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

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

于 2010-03-20T12:47:58.550 回答
1

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

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

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

于 2010-08-07T07:51:18.923 回答