我的纯DotNET库在非托管桌面应用程序中作为插件运行。我一直在获得一个稳定的(虽然很低)崩溃报告流,似乎表明GDI句柄有问题(错误消息中的字体等恢复到系统字体,各种控件的显示中断,大规模崩溃后不久)。
我的表单几乎没有控件,但我在用户控件中做了很多GDI +绘图。什么是告诉我正在使用多少句柄,甚至泄漏的好方法?
谢谢, 大卫
答案 0 :(得分:5)
从Ray Vega的回答中GDIView开始,我发现this tip:
[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
隐藏在后台窗口中时,我们会更新Label
控件的文本。这会导致GDI泄漏字体句柄。为了解决这个问题,我们将逻辑更改为不更新UserControl
,除非它当前在屏幕上可见。为了确定它是否可见,我们记录了{{1}}上次绘制的时间。
答案 1 :(得分:3)
除了性能监视器,您还可以尝试使用旧的任务管理器。
选中流程标签,然后点击View
> Select Columns...
并检查GDI对象。
答案 2 :(得分:3)
看一下GDIView(免费软件):
GDIView是一个独特的工具 GDI句柄列表(画笔, 钢笔,字体,位图等) 每个过程都打开了。它显示 每种类型的GDI的总数 处理,以及详细 有关每个句柄的信息。这个 工具对开发人员有用 需要追踪GDI资源泄漏 他们的软件。
alt text http://www.nirsoft.net/utils/gdiview.gif
注意默认情况下禁用自动刷新,但可以按特定时间间隔启用和配置:Options -> Auto Refresh -> Every [N] seconds
答案 3 :(得分:2)
我过去不得不处理同样的问题。为了检查应用程序分配的GDI对象数量,您可以使用名为GDIUsage的免费工具。
在我的情况下,应用程序崩溃了,因为它分配了超过 10.000 GDI对象,这是Windows XP中的硬限制。可能值得研究。
我在这里发表了关于这个问题的博客:
http://megakemp.com/2009/02/25/gdi-memory-leak-in-windows-forms/
答案 4 :(得分:1)
很容易从TaskMgr.exe,Processes选项卡中看到。查看+选择列,勾选GDI对象。
您的描述确实与手柄泄漏相匹配。这不应该在托管程序中真正发生,终结器应该照顾你忘记调用Dispose()。除非你不消耗大量垃圾收集堆空间。它也可能是非托管应用程序泄漏句柄,它们经常这样做。
答案 5 :(得分:1)
如果您还没有这样做,请确保在您正在使用的任何GDI +绘图对象上调用IDisposable.Dispose。通常使用C#using
构造来执行此操作,例如:
using(Brush brush = ...)
{
...
}
静态代码分析工具(如FxCop或Visual Studio Team System版本中内置的版本)可以帮助您检测无法调用Dispose的情况。
无法以这种方式调用Dispose是一个潜在的句柄泄漏,因为在垃圾收集器看起来合适之前不会回收句柄。
答案 6 :(得分:1)
GDIObj,冯远提供的免费实用工具作为他的书Windows Graphics Programming: Win32 GDI and DirectDraw的示例程序可能会有用。
与任务管理器不同,它提供了不同GDI句柄类型的进一步细分计数,包括DC,Region,Bitmap,Palette,Font,Brush等。
(但是,它仅提供计数信息,而GDIView提供有关句柄的更多详细信息。)