GDI对象泄露分析

最近在魔改一个比我还老的MFC项目……主要是用于读取dxf文件进行数据分析并且绘制图像,花了两三天弄下来之后已经变得有模有样了,结果我在无意间拖动的时候发现我只要对这个图像多拖动一会,程序竟然就自动奔溃了……然后我就开始了问题分析之旅。

GDI就是操作系统提供给显示器之类的输出设备的标准,在mfc中有不少GDI对象类比如CBrush刷子,CPen笔等,在绘制之前的初始化中会创建GDI对象,将其选入Windows设备描述表中,使用完成之后恢复设备描述表的原GDI对象,再删除创建出来的这个GDI对象,具体使用例如:

HPEN pen = CreatePen(PS_SOLID, 0, rgbcolor);
oldpen = (HPEN)SelectObject(hdc, pen);
MoveTo(x, y);
...
SelectObject(hdc, oldpen);
DeleteObject(pen);

利用任务管理器可以监控一个程序的GDI对象使用数量,打开任务管理器之后转到详细信息,右键第一列选择“选择列”,勾选GDI对象后即可。我对软件的GDI对象进行监控之后发现GDI的对象上升快的吓人,主要因为这个老项目每一次鼠标进行像素点的移动都会重绘整个图像。通过滚轮放大缩小对单次绘制的GDI对象泄露数量进行观察,发现是6个,刚好我这个图像里也有六个文字,于是进行了对应的跟踪调试,发现原来是我在魔改的时候忘记注释了一行代码,导致绘制所有TEXT对象的时候没有及时回收GDI对象,从而导致的泄露。真是debug半年,改改一分钟……

不过这个老项目本身也有一个地方存在GDI对象泄露,所以一开始误导了我的方向……

原代码中有一处,每次通过GetDC()来判断鼠标的移动位置合法性,这样返回的指向CDC的指针没有保存,而他本身不会自动释放,就会导致GDI资源的泄露,需要用以下形式代替:

CDC* pDC = this->GetDC();
...
ReleaseDC(pDC);

热评文章