DotNET 应用程序中的 GDI 句柄
我的纯 DotNET 库作为非托管桌面应用程序中的插件运行。我收到了稳定的(虽然低)崩溃报告流,这些报告似乎表明 GDI 句柄存在问题(错误消息中的字体等。恢复为系统字体,各种控件的显示崩溃,不久后发生大规模崩溃) )。
我的窗体几乎没有控件,但我在用户控件中进行了大量 GDI+ 绘图。有什么好方法可以知道我正在使用多少个手柄,甚至有多少个手柄泄漏?
谢谢, 大卫
My pure DotNET library runs as a plugin inside an unmanaged desktop application. I've been getting a steady (though low) stream of crash reports that seem to indicate a problem with GDI handles (fonts in error messages etc. revert to the system font, display of all sorts of controls break down, massive crash shortly after).
My Forms have few controls, but I do a lot of GDI+ drawing in User controls. What's a good way to tell how many handles I'm using, or even leaking?
Thanks,
David
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
从 Ray Vega 的答案开始,我发现 此提示:
GDIView 通知它是字体对象被泄露;然后,我将对
GetGuiResources
的调用添加到我们的日志记录代码中,以检测触发对象创建的时间点。在我们的例子中,当
Label
控件的父UserControl
隐藏在后台窗口中时,我们更新了Label
控件的文本。这会导致 GDI 泄漏字体句柄。为了解决这个问题,我们更改了逻辑,除非标签当前在屏幕上可见,否则不更新标签。为了确定它是否可见,我们记录了UserControl
上次绘制的时间。Starting with GDIView from Ray Vega's answer, I found this tip:
GDIView informed that it was font objects that were being leaked; I then added calls to
GetGuiResources
into our logging code to detect at which point the object creation was being triggered.In our case, we had the text of a
Label
control being updated when its parentUserControl
was hidden in a background window. This would cause GDI to leak font handles. To fix it, we changed our logic to not update theLabel
unless it was currently visible on screen. To determine whether it was visible, we keep a record of when theUserControl
was last painted.看一下 GDIView (它是免费软件):
(来源:nirsoft.net)
注意 默认情况下禁用自动刷新,但可以启用并配置特定时间间隔:
Options ->自动刷新->每[N]秒
Take a look at the GDIView (it's freeware):
(source: nirsoft.net)
Note that the auto-refresh is disabled by default, but it can enabled and configured for specific intervals:
Options -> Auto Refresh -> Every [N] seconds
除了性能监视器之外,您还可以尝试使用旧的任务管理器。
检查处理选项卡,然后单击
查看
>选择列...
并检查 GDI 对象。Besides the performance monitor, you can try the good old Task Manager.
Check the Process tab and click
View
>Select Columns...
and check the GDI objects.我过去也曾遇到过同样的问题。为了检查您的应用程序分配了多少 GDI 对象,您可以使用名为 GDI使用。
在我的例子中,应用程序崩溃是因为它分配了超过 10.000 个 GDI 对象,这是 Windows XP 中的硬限制。也许值得研究一下。
我已经在博客中讨论了这个问题:
http://megakemp.com/2009/02 /25/gdi-内存泄漏-windows-forms/
I've had to deal with the same kind of problem in the past. In order to inspect how many GDI objects your application is allocating you can use a free tool called GDIUsage.
In my case the application was crashing because it was allocating more than 10.000 GDI objects, which is a hard limit in Windows XP. It might be worth looking into it.
I've blogged about this problem here:
http://megakemp.com/2009/02/25/gdi-memory-leak-in-windows-forms/
从 TaskMgr.exe 的“进程”选项卡中很容易看到。查看+选择列,勾选GDI对象。
您的描述确实符合句柄泄漏。这实际上不应该发生在托管程序中,终结器应该照顾您忘记调用 Dispose() 的情况。除非你不消耗大量垃圾收集堆空间。也可能是非托管应用程序泄漏句柄,他们经常这样做。
It is easy to see from TaskMgr.exe, Processes tab. View + Select Columns, tick GDI Objects.
Your description indeed matches a handle leak. That shouldn't really happen in a managed program, the finalizer should take care of you forgetting to call Dispose(). Unless you don't consume a lot of garbage collected heap space. It could also be the unmanaged app leaking handles, they very often do.
如果您还没有这样做,请确保对您正在使用的任何 GDI+ 绘图对象调用 IDisposable.Dispose。您通常会使用 C#
using
构造来执行此操作,例如:静态代码分析工具(例如 FxCop)或 Visual Studio Team System 版本中内置的版本可以帮助检测无法调用 Dispose 的情况。
未能以这种方式调用 Dispose 可能会导致句柄泄漏,因为在垃圾收集器认为合适之前,句柄不会被回收。
If you are not already doing so, make sure you call IDisposable.Dispose on any GDI+ drawing objects you are using. You would usually do this with the C#
using
construct, e.g.:Static code analysis tools such as FxCop or the version built into Team System editions of Visual Studio can help to detect cases where you fail to call Dispose.
Failure to call Dispose in this way is a potential handle leak, as the handle won't be reclaimed until the garbage collector sees fit.
GDIObj,冯远提供的免费实用程序,作为他的书的示例程序,Windows图形编程:Win32 GDI和DirectDraw可能有用。
与任务管理器不同,它提供了不同 GDI 句柄类型的进一步细分的计数,包括 DC、区域、位图、调色板、字体、画笔等。
(但是,它仅提供计数信息,而 GDIView 提供有关句柄的更多详细信息。)
GDIObj, a free utility provided by Feng Yuan as a sample program for his book, Windows Graphics Programming: Win32 GDI and DirectDraw might be useful.
Unlike Task Manager, it provides counts of a further breakdown of different GDI handle types including DC, Region, Bitmap, Palette, Font, Brush, etc.
(However, it only provides count info while GDIView provides more detail about the handles.)