GDI洩漏排查經驗零散總結

hsqcarter發表於2020-05-29

1.GDI物件以及釋放方法:

GDI物件

產生方法

銷燬方法

點陣圖(HBITMAP)

CreateBitmap,CreateBitmapIndirect,

CreateCompatibleBitmap,CreateDIBitmap,

CreateDIBSection,CreateDiscardableBitmap

DeleteObject

畫刷(HBRUSH)

CreateBrushIndirect,CreateDIBPatternBrush,

CreateDIBPatternBrushPt,CreateHatchBrush,

CreatePatternBrush,CreateSolidBrush

DeleteObject

裝置上下文(HDC)

CreateDC

DeleteDC,ReleaseDC

字型(HFONT)

CreateFont,CreateFontIndirect

DeleteObject

記憶體DC(HDC)

CreateCompatibleDC

DeleteDC

調色盤(HPALETTE)

CreatePalette

DeleteObject

畫筆(HPEN)

CreatePen,CreatePenIndirect

DeleteObject

區域(HRGN)

CombineRgn,CreateEllipticRgn,

CreateEllipticRgnIndirect,CreatePolygonRgn,

CreatePolyPolygonRgn,CreateRectRgn,

CreateRectRgnIndirect,CreateRoundRectRgn,

DeleteObject

2.資源切換時容易出現的GDI洩漏:

1)SelectObject、SetBitmap、SetIcon、SendMessage(訊息為BM_Bitmap時),會返回之前使用的GDI資源,不再使用的GDI資源需要及時釋放(記錄好之前使用的系統GDI資源,在結束時還原設定並釋放掉申請的GDI資源);

2)SelectObject 選入的使用者建立的GDI資源,需要在不再使用時選出並釋放。

3)使用的控制元件有時候會因為一些原因在Res資源中新增過圖示等GDI資源,導致在程式碼中做控制元件初始化時設定新圖示產生了GDI洩漏(從程式碼上來看是第一次設定圖示就引起了洩漏)。

3.LoadImage函式:

LoadImage函式可以載入Bitmap、Icon、Cursor三種GDI資源,需要分別使用DeleteObject、DestroyIcon、DestroyCursor來釋放,不可以混用。

LoadImage函式生成的GDI資源使用後就可以釋放,不會因為立即釋放後導致前面設定的資源不起作用。

 

4. CImageList儲存的GDI資源需要呼叫DeleteImageList來釋放。

 

5.CDC、CPEN、CBrush等MFC包裝的GDI類,在其解構函式中會呼叫DeleteObject函式取釋放資源。

 

6.建立GDI資源的函式和釋放GDI的函式使用次數要匹配,比如:視窗Create、OnInitDialog、以及訊息響應等函式會因為一些原因多次呼叫(比如DoModal如果被迴圈呼叫是會引起視窗的Create和OnInitDialog反覆觸發),如果在這類函式中申請GDI資源需要特別注意,因為一般作為成員變數的GDI資源的釋放在解構函式中的話就只會被呼叫一次。

 

7.給外部模組呼叫的函式中如果包含了GDI資源的申請需要在函式頭註釋,提醒呼叫者需要手動釋放(往往函式被包裝幾層後外層函式呼叫者很容易忽略釋放)。

 

8.少量程式碼是可以根據程式碼靜態檢視或者分模組除錯來找出GDI洩漏位置,但是大量程式碼排查需要藉助工具才比較有效率,這裡推薦Deleaker這款工具(GDI洩漏和記憶體洩漏都可以準確的找出程式碼行)。

 

相關文章