关于非托管资源GDI对象泄漏-解决问题随笔

本文详细介绍了在复杂系统中定位非托管资源泄漏的过程,分享了一款监测非托管资源句柄的工具,并探讨了GDI对象泄漏的具体案例。通过实验发现,特定的DC句柄资源被错误地计入AllGDI而非DC列,揭示了第三方组件引发的资源泄漏问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

要在一个庞杂的系统之中找到非托管资源泄漏的位置,是一个极为头痛的事情,所以在托管平台操作非托管资源一定要谨慎,用完便要及时释放,否则埋下的雷,过一段时间要费极大的代价和心力去找。更别提是要在别人杂乱的代码之中去找这颗雷了,就像我这次一样,都要累吐了。还好找到一个监测非托管资源句柄的工具,英文的,粗略的把程序汉化了一下,有想用的可以下载,这个是目前为止最新的版本。

*************************************

更新,遗憾的是,用该工具并未监测到常规GDI对象的泄漏情况,但却监测到总占用GDI节节攀升,但这没有什么帮助:

因为在任务管理器中也可以看到GDI对象的总占用数量,看了一下该工具作者的描述,他这样写道:

'GDI Total' and 'All GDI' columns

The 'GDI Total' column (a new column added on v1.05) displays the total number of all GDI handles found in the GDI table for the specified process. This means that 'GDI Total' column display the sum of the following columns: Pen, ExtPen, Brush, Bitmap, Font, Palette, Region, DC, Metafile DC, Enhanced Metafile DC, and Other GDI.
The 'All GDI' value is taken from Windows API call (GetGuiResources), and it usually contains a value larger than 'GDI Total', probably because it also counts some internal kernel GDI objects that are not included in the GDI objects table of the process.

Notice: If you have a problem that the 'All GDI' value is increased, while there is no leak with the other GDI values, it means that you probably have a leak in the creation of icons or cursors (Icons and cursors are created without destroying them later).

依照上面所述,只有图标和游标的句柄资源才会被计入到All GDI列之中,但我的验证结果却非如此,利用平台调用的方式去调用user32.dll的GetWindowDC接口创建DC句柄,却没有被计入DC列之中,而是计入了All GDI列之中,代码如下:

        [System.Runtime.InteropServices.DllImport("user32.dll")]
        static extern IntPtr GetWindowDC(IntPtr hWnd);
        [System.Runtime.InteropServices.DllImport("user32.dll")]
        static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);

        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                for(int i = 0;i < 1000; i++)
                {
                    GetWindowDC(this.Handle);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            
        }

运行结果:

这里点击了3次按钮,GET了3000个DC句柄,从结果上面可以看出全部加入了All GDI列,加上程序本身初始的句柄数,总共是3030个。(这个经过后来测试,好像是因为系统是64位导致的,这个软件的64位版好像有点问题,我使用32位的XP虚拟机就没有此问题。)

另外经过查阅相关资料,得知对于非托管资源GDI对象的创建和释放,一般由以下几种方法来执行:

Create出来的GDI对象,都要用DeleteObject来释放;Create出来的DC,都要用DeleteDC来释放,GetDC得出的DC,要用ReleaseDC来释放。

唉……接着找吧。

******************************************

再度更新,找到泄漏位置了,既然是一个第三方的组件导致的,一个成型的组件居然有这么一个恶劣的问题,也没有源码,没辙了,以后有时间看能不能把这个控件给换掉吧,不过估计不大可能实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值