打开任务管理器,点击菜单“查看”——“选择列”,勾上所有项,“确定”。运行自己的程序,进行各种操作,并查看任务管理器中GDI对象和句柄数的变化。
如果在某次可逆操作中,例如,弹出一个对话框,然后关闭,GDI对象或句柄数先增加了,然后减少了,但是总量还是增加了,说明存在内存泄露,GDI对象没有被及时回收。如果句柄数出现类似情况,则情况复杂很多。
接下来,注释掉某些代码,编译运行并继续观察,逐步定位导致内存泄露的代码段。
实例:
某程序运行时,弹出一个窗口,再关闭,GDI对象数目就增加了一个。经过一个多小时的分析,最后定位出问题所在,如下:
LOGFONT logfont={0};
GetObject(m_font, sizeof(logfont), &logfont);
logfont.lfHeight = -MulDiv(size, GetDeviceCaps(::GetDC(NULL), LOGPIXELSY), 72);
SetFont(&logfont);
这段代码是用来改变窗口的字体大小的,size是字体的磅数,但是LOGFONT是按像素计算字体大小的,所以,需要转换字体的磅数为像素大小。这里只转换了高度,因为设置字体大小时,只需要高度就可以了。 logfont.lfHeight = -MulDiv(size, GetDeviceCaps(::GetDC(NULL), LOGPIXELSY), 72); 这句代码是从网上搜索到的、转换字体磅数为像素大小的代码,我也没有去细看,直接copy了一下,毕竟代码很短,乍一看,真没什么问题。然而,这里使用了GetDC,这将导致GDI对象增加,所以,应该调用DeleteDC回收,这就是问题所在。
修改后的代码为:
LOGFONT logfont={0};
GetObject(m_font, sizeof(logfont), &logfont);
HDC hdc=::GetDC(NULL);
ASSERT(hdc!=NULL);
logfont.lfHeight = -MulDiv(size, GetDeviceCaps(hdc, LOGPIXELSY), 72);
::DeleteDC(hdc);
SetFont(&logfont);