哪些 GDI 对象可能会被泄漏,但不会被枚举为已知的 GDI 对象类型?

问题描述 投票:0回答:1

我有一个进程不断循环运行某些东西。它打开表单,处理其中的内容,然后关闭它们。一段时间后,该过程开始出现一些错误并最终崩溃。

查看任务管理器,我注意到该进程达到了 10,000 个 GDI 对象的限制。这个进程一定在某个地方有 GDI 对象泄漏。

我下载了GDIView.exe,注意到“所有GDI”列随着时间的推移不断增加,但列出的GDI对象类型的数量是合理的并且没有增加。

例如,请参阅下面的屏幕截图。 GDIView.exe 显示 1,782 个“其他 GDI”对象。其余列显示 4 个位图、1 个区域和 0 个其他类型的对象:

GDIView.exe showing 1,782

我下载了一个脚本“DumpGdi.txt”来帮助 WinDbg 显示内存转储中的 GDI 对象计数。尽管任务管理器和 GDIView.exe 显示大量 GDI 对象,但该列表在任何给定时间仅计数不到 100 个 GDI 对象。

GDIView.exe 中的“所有 GDI”列中累积的 GDI 对象是什么?我如何更好地了解它们?我想知道泄漏了什么,这样我就可以知道在我的代码中寻找什么。

Windows 任务管理器也显示相同高度的 GDI 对象。

我没有看到任何托管对象内存泄漏。如果存在托管对象,如果我在 WinDbg 中运行 !DumpObj -type 命令,我就可以看到它们,并且我可以使用 !GCRoot 来查找它们被泄漏的原因。我还希望看到大量图标、字体和可能的位图对象,但这些类型在 GDIView.exe 输出中似乎不是问题。

我在 DebugDiag 2.x 中运行了 LeakTrack.exe。除了指出 CLR 可能是泄漏源之外,报告输出没有太大帮助。

windows memory-leaks windbg gdi
1个回答
0
投票

我使用 Microsoft Performance HUD 工具发现了该问题。当我使用性能 HUD 运行测试应用程序时,该工具向我显示问题是 CURSOR 用户对象和 PAL GDI 对象都被泄漏。

“调用堆栈”选项卡向我显示了泄漏的根本原因是以下代码行,它将位图对象转换为图标。此行创建一个需要处置的临时 GDI 句柄。

this.Icon = Icon.FromHandle(bitmap.GetHicon());

修复方法是处理临时句柄:

[System.Runtime.InteropServices.DllImport("user32.dll", CharSet = CharSet.Auto)]
extern static bool DestroyIcon(IntPtr handle);

IntPtr handle = IntPtr.Zero;
try
{
    handle = bitmap.GetHicon();
    this.Icon = Icon.FromHandle(handle);
}
finally
{
    if (handle != IntPtr.Zero)
    {
        DestroyIcon(handle);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.