http://blog.csdn.net/xyl_nuaa/article/details/6827365
最近遇到这样一个问题:
曾经写的一个mfc绘图程序,实时刷新显示文件数据,其中用到了GDI资源,程序刚开始运行的时候没问题,但随着时间的蔓延,开始报错:“必须的资源无法得到”。
于是开始google,baidu,说是GDI资源泄漏的问题。
接着找到用到GDI资源的地方,主要代码如下(在OnPaint()中):
CClientDC dc(this);
CDC MemDC;
CBitmap MemBitmap;
MemDC.CreateCompatibleDC(NULL);
MemBitmap.CreateCompatibleBitmap(&dc,rect.Width(),rect.Height());
int nDCSave = MemDC.SaveDC();
MemDC.SelectObject(&MemBitmap);
CPen penYellow(PS_SOLID,1,YELLOW);
CPen penRed(PS_SOLID,1,RED);
CPen penRed2(PS_SOLID,2,RED);
CPen penGreen(PS_SOLID,1,GREEN);
CPen penBlue(PS_SOLID,1,BLUE);
CPen penBlack(PS_SOLID,1,BLACK);
// CPen *pOldPen = MemDC.SelectObject(&penYellow);
MemDC.SelectObject(&penYellow);
。。。
//绘制操作
。。。
//绘图完成后的清理
MemDC.RestoreDC(nDCSave);
MemBitmap.DeleteObject();
MemDC.DeleteDC();
看来看去也没什么可疑的,该释放的我也做了释放了,关于CPen 来说,因为是CGdiObject的派生类,在析构函数中调用了DeleteObject()函数,所以不需要显式释放,CBrush 同理。但是如果CPen这里调用的是不带参数的构造函数的话,比如 CPen PenYellow; 这样的话后面必须还要调用CreatePen等函数来对CPen进行初始化工作,此时是需要显式释放的,即手动调用PenYellow.DeleteObject();
这里是没什么错了,那到底错在哪里呢?
将任务管理器中GDI对象打开,专门查看程序的GDI资源利用情况,发现只要程序一产生一个重绘事件(比如我拖动,拖动任务管理器窗口,放大缩小程序窗口),GDI资源就会增多。这种现象表示问题十有八九在OnPaint()函数中,但是我将程序用到的所有OnPaint()函数都查看过了,没什么可疑的,再次排查时,突然想到OnCtrlColor函数也会在界面刷新时调用,一查看果然发现问题,OnCtrlColor里返回的画刷的句柄因为是局部变量而没有被释放,改为成员变量,作如下修改后,解决问题
if(nCtlColor == CTLCOLOR_DLG || nCtlColor == CTLCOLOR_STATIC)
{
。。。
// HBRUSH B = CreateSolidBrush(RGB(78,139,169)); //背景色
// return B;
m_brBrush.DeleteObject();
m_brBrush.CreateSolidBrush(RGB(78,139,169));
return static_cast <HBRUSH> (m_brBrush.GetSafeHandle());
}
其中注释掉的为原来的代码。
附:GDI资源释放表
Resource Allocation Routine Cleanup Routine Cleanup Required?
================================================================================
Accelerators LoadAccelerators N/A No
Atoms GlobalAddAtom GlobalFreeAtom Yes
Bitmaps CreateBitmap DeleteObject Yes *
CreateBitmapIndirect DeleteObject Yes *
CreateCompatibleBitmap DeleteObject Yes *
CreateDIBitmap DeleteObject Yes *
CreateDiscardableBitmap DeleteObject Yes *
LoadBitmap DeleteObject Yes *
Brushes CreateBrushIndirect DeleteObject Yes
CreateDIBPatternBrush DeleteObject Yes
CreateHatchBrush DeleteObject Yes
CreatePatternBrush DeleteObject Yes
CreateSolidBrush DeleteObject Yes
Carets CreateCaret DestroyCaret No #
Clipboard OpenClipboard CloseClipboard Yes
Comms Ports OpenComm CloseComm Yes
Cursor CreateCursor DestroyCursor Yes
LoadCursor N/A No
DC CreateDC DeleteDC Yes
CreateCompatibleDC DeleteDC Yes @
GetDC ReleaseDC Yes
GetWindowDC ReleaseDC Yes
BeginPaint EndPaint Yes
Dialog Box CreateDialog DestroyWindow No
CreateDialogIndirect DestroyWindow No
CreateDialogIndirectParam DestroyWindow No
CreateDialogParam DestroyWindow No
File OpenFile _lclose No
Fonts CreateFont DeleteObject Yes
CreateFontIndirect DeleteObject Yes
AddFontResource RemoveFontResource Yes
GDI Stock Obj GetStockObject N/A No &
Hook SetWindowsHook UnhookWindowsHook Yes
IC CreateIC DeleteDC Yes
Icon CreateIcon DestroyIcon Yes
LoadIcon N/A No
Library LoadLibrary FreeLibrary Yes
Memory AllocDStoCSAlias FreeSelector Yes
AllocSelector FreeSelector Yes
GlobalAlloc GlobalFree No
GlobalDOSAlloc GlobalDOSFr No
GlobalFix GlobalUnfix No
GlobalLock GlobalUnlock No
GlobalPageLock GlobalPageUnlock No
GlobalRealloc GlobalFree No
GlobalWire GlobalUnwire No
LocalAlloc LocalFree No
LocalLock LocalUnlock No
LocalRealloc LocalFree No
Menu CreateMenu DestroyMenu No %
CreatePopupMenu DestroyMenu No %
LoadMenu DestroyMenu No %
LoadMenuIndirect DestroyMenu No %
GetSystemMenu N/A No
MetaFile CreateMetaFile DeleteMetaFile Yes
Palette CreatePalette DeleteObject Yes
Pen CreatePen DeleteObject Yes
CreatePenIndirect DeleteObject Yes
Regions CreateEllipticRgn DeleteObject Yes
CreateEllipticRgnIndirect DeleteObject Yes
CreatePolygonRgn DeleteObject Yes
CreatePolyPolygonRgn DeleteObject Yes
CreateRectRgn DeleteObject Yes
CreateRectRgnIndirect DeleteObject Yes
CreateRoundRectRgn DeleteObject Yes
Resource AllocResource FreeResource No
FindResource N/A No
LoadResource FreeResource No
LockResource UnlockResource No
Sound OpenSound CloseSound Yes
String LoadString N/A No
Thunk MakeProcInstance FreeProcInstance No
Timer SetTimer KillTimer No
Window CreateWindow DestroyWindow No
CreateWindowEx DestroyWindow No
Notes:
------
* Bitmaps must be disconnected from a DC before being freed.
% Menus must be freed before an application exits if the menu is not
connected to any window.
@ A DC must be disconnected from bitmaps before being freed.
# If a bitmap is specified for the Caret, it must be freed.
& Calls to DeleteObject do not harm stock objects.