在Windows应用程序开发中,GDI(图形设备接口)句柄泄漏是一个常见的问题,它可能导致应用程序性能下降甚至崩溃。本文将介绍如何使用Windows调试器来诊断和修复GDI句柄泄漏问题,特别是字体和图标泄漏的情况。
在开始使用调试器之前,可以通过搜索代码库中的BeginPaint()
和EndPaint()
函数调用来初步诊断GDI句柄泄漏。这两个函数之间的GDI代码需要仔细检查,确保所有创建的句柄都被正确删除。
使用任务管理器,可以在“详细信息”标签页中添加一个“GDI对象”列,以查看每个进程当前打开的GDI句柄数量。一个进程最多可以打开10000个GDI句柄,而系统范围内所有进程的句柄数量上限为65535。
为了缩小泄漏的GDI对象类型,可以使用GDIView(基于UI)或GDIInquiry.exe(基于控制台)工具。通过比较UI语言更改前后的GDI对象数量,可以发现字体对象的数量每次更改时都会增加,而其他GDI对象的数量保持不变。
在MSDN页面上找到字体创建函数的列表后,可以使用WinDbg附加到进程,并在这些函数上设置断点。需要注意的是,GDI句柄也可以由USER32.DLL中的函数返回,因此也需要检查MSDN文档。
在WinDbg中,可以使用x
命令进行不区分大小写的搜索,以找到以createfont
开头的符号名称。然后,可以在这些函数上设置断点,并指定在断点命中时执行的命令,例如显示调用堆栈和参数。
在修复泄漏时,发现在CEdit派生类中,一个HFONT成员被创建并设置为当前字体,但没有在析构函数中调用DeleteObject()
。修复这个泄漏后,字体对象的数量稳定了,但“所有GDI”的数量在每次语言更改时仍然迅速增加。
经过审查所有图标和光标创建代码后,发现泄漏来自多次调用的LoadImage
函数。修复方法是将图标加载为共享的(LR_SHARED),这意味着只有一个图标实例会被加载,并在应用程序运行结束时释放。
读者可能会问为什么没有使用!htrace命令,这个命令专门用于跟踪句柄泄漏。!htrace命令只适用于真正的内核句柄,不能用于跟踪GDI句柄泄漏。
本文详细介绍了如何查找和修复字体和图标泄漏。另一种常见的GDI泄漏类型是位图,本文没有涉及。请确保删除由USER32.DLL中的GetIconInfo()
、GetIconInfoExW()
或GetIconInfoExA()
返回的位图句柄。如果觉得本文有用,请考虑点赞,以鼓励继续撰写更多相关内容。