寫這邊初衷是記錄效能優化開發過程的點滴,以及期間的各種問題排查,修正等, 也為後續同仁減少不必的期間痛苦, 鑑於經驗和水平,以及寫作能力,如果有問題,望及時糾正:
下面開始記錄點滴:
最近測試反饋,程式用著用著就莫名的異常,沒有具體點規律, 做為開發,就討厭這種莫名的問題,後面排查,通過任務管理器檢視相關資訊,其實這個管理器是很好的一把利器, 通過設定「檢視-選擇列」, 可以檢視很多資訊,如記憶體,gdi,控制代碼,執行緒數等, 為我們前期排查提供依據。
排查之後,發現程式gdi會快速的增加,其正常,達到9999之後就不正常或者直接退出, 以此排查是gdi洩露導致程式問題,模組比較多,所以排查也是耗時耗力,通過測試協助,將問題限定在其中某乙個模組。但是其中的**也是10多個類, 且怎麼可以定位呢?
這個裡有個很放方便的工具,gdindicator.exe, 詳細資訊參考如下連線
根據該工具可以直觀的檢視到那個資源洩露,如dc一致增長,當總gdi數達到10000就異常,進而在模組**中排查問題所以,如果一切順利則萬事大吉,否則就要針對相關自繪**逐步排查,已我最近排查為例:
定位到具體模組, 逐步排查自繪等相關邏輯,發現沒有問題,進而懷疑呼叫底層封裝的控制項有問題,這就坑了,底層是cvirtualgridctrl基礎上做一層封裝,其中有個介面會根據當前文字獲取高度,具體**片段如下:
案例一:比較直觀的洩露
int calcaptionheight()
int nheight = 0;
cvirtualgridctrl* pgrid = phead->getgrid()
if(pgrid )
cdc* pdc = pgrid->getdc();
if(pdc != null)
crect rc(0,0,0,0);
pdc ->drawtext(strcaption, strcaption.getlength(), rc, dt_calcrect);
nheight = rc.height();
pgrid->releasedc(pdc ); // 之前沒有改行**
return nheight
該介面為在繪製表頭時使用,且為底層控制項介面, 客戶端程式使用好多年,均沒有出現異常想象, 為什麼現在會有呢? 主要原因如下:
首先,該介面存在gdi洩露,但是由於呼叫的次數不多, 所以一般情況沒有什麼問題;
其次, 因為不正常呼叫介面,導致大量的重新整理操作,進而不斷呼叫calcaptionheight(), 進而匯出程式異常。
案例一:比較隱晦的:
我們程式中經常將做成乙個list,然後用cimagelistobj等進行載入, 主要是為減少資源數量,以及程式方便,然後使用時會利用
如下**:
hicon hicon = cimagelistobj.extracticon(nind)
iconinfoinfor
::geticoninfor(hicon,&infor)
bitmapbmp
::getobject(infor.hbmcolor,sizeof(bitmap), (lpvoid)& bmp);
intnwidth = bmp.bmwidth
intnhight = bmp.bmheigt
::drawiconex(pdc->getsafehdc(),cx,cy,hicon,nwidth, nhieht,0,null, di_normal);
以上通過傳遞圖示索引即可畫對應的, 以上**存在嚴重洩露
主要如下
1, 獲取的iconinfo infor 一定要釋放其中的hbitmap成員,呼叫如下:
::deleteobject(infor.hbmcolor)
::deleteobject(infor.hbmmask)
2, 獲取的bitmap 也要進行釋放, 呼叫如下:
::deleteobject((hgdjobj)&bmp)
3,獲取的hicon hicon,一定要記得是否 呼叫如下:
::desstroyicon(hicon)
發先該問題之後,根據gdindicator.exe工具,是無法顯示hicon的資源, 然後就總數一致增加,最後還好該出自繪**不多,然後一段一段注釋,排查到上面帶顏色的洩露,然後查資料等, 合適問題。
期間還有個小插曲, 排查到問題之後, 很愉快的解決,但是第二天測試反饋還存在,就鬱悶,以為版本沒有發布好, 後來排查, 居然少了::deleteobject((hgdjobj)&bmp)
這行**,進而還是異常, 看來針對問題還是要保持一定的警惕性
通過以上排查,足以可以,類似這樣的問題,有多麼坑, 所以平時寫**時,要每一行一行審閱, 常見的問題,一定要銘記於心,為此整理如下想資料,便於大家了解,詳見附件文件描述, 如下簡要描述gdi
作為還在繼續奮戰在window ui 做客戶端下同仁們,應該對其深有認識:
如上資源為系統資源,其建立是受限的,主要受限如下: 系統本身對限制和登錄檔最大值的設定,具體如下:
1,系統中每個程序建立gdi是有限制的,理論上為64k,為什麼64k呢? 因為gdi實為window維護的一些資料結構,基於穩定和安全將所以gdi物件交系統管理,使用者通過獲取控制代碼進行操作。
window2000中,控制代碼實際為dword型別, 佔32為位元組,因此理論上為64。
2, 每個程序建立最大數還受作業系統中gdi最大數的限制,當達到一定數量時,則不程序建立, 不同的作業系統可能不同,沒有做考證。
3,程序建立最大數,還受限於登錄檔設定最大數影響,主要位於key_local_machine/ software/microsoft/windows nt/currentversion/windows下的"gdiprocesshandlequota" 項所設定的值, 預設值為10000, 所以當達此致獲取就失敗, 如果程式為做保護,進而就異常。
程式效能與穩定優化 靜態變數的感想
鑑於專案之前排查乙個偶發的問題,最後居然定位在區域性靜態變數導致,所以記錄一下,同時要明白靜態變數的作用,及使用的場景,否則很容易出錯!具體模擬 如下 void function static int nindbac 1 if 1 nindbac nindbac m vectables.size m...
優化程式效能
編寫高效程式需要兩個活動 第一,我們必須選擇一組最好的演算法和資料結構 第二,我們必須編寫出編譯器能夠有效優化以轉換成高效可執行 的源 這裡,我們主要講述後者。首先,我們討論一下為什麼要編寫高效程式。不難想象,如果本來要用 天執行完的程式,經過優化只需要 天就可執行完,這是一件多麼令人振奮的 事啊。...
優化程式效能
l 消除迴圈的低效率 n 對於迴圈中的過程呼叫盡量移出迴圈外,例如 nfor i 0 i strlen s i strlen 函式為線性增長 在字串長度很大時 很消耗系統資源 n 減少不必要的儲存器引用,將儲存器引用儲存在臨時變數中.l 處理器優化 即充分利用儲存器流水線操作的吞吐量 n 迴圈展開,...