可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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
回答1:
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/
回答2:
Starting with GDIView from Ray Vega's answer, I found 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 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 parent UserControl
was hidden in a background window. This would cause GDI to leak font handles. To fix it, we changed our logic to not update the Label
unless it was currently visible on screen. To determine whether it was visible, we keep a record of when the UserControl
was last painted.
回答3:
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.
回答4:
Take a look at the GDIView (it's freeware):
GDIView is a unique tool that displays
the list of GDI handles (brushes,
pens, fonts, bitmaps, and others)
opened by every process. It displays
the total count for each type of GDI
handle, as well as detailed
information about each handle. This
tool can be useful for developers that
need to trace GDI resources leak in
their software.
alt text http://www.nirsoft.net/utils/gdiview.gif
Note that the auto-refresh is disabled by default, but it can enabled and configured for specific intervals: Options -> Auto Refresh -> Every [N] seconds
回答5:
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.
回答6:
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.:
using(Brush brush = ...)
{
...
}
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.
回答7:
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.)