SleuthQA CodeWatch 跟蹤後臺服務資源泄漏

某日,一個我編寫的Delphi 應用(dll 插件)被發現運行一段時間後,系統的PF 佔用其高且下不來。

後在任務管理器中發現此應用所在的exe 在運行期間的句柄計數會穩定累積增加, user對象、GDI對象計數未發現明顯異常。

使用SleuthQA CodeWatch( 以下簡稱 CW) 調試此dll, 過程如下:

 

 

Step1. 準備工作

 

1.1  CW-File-NewProject,選擇要分析的模塊,即本應用的dll

 

 

 

 

 

1.2 選擇模塊對應的Host EXE

 

 

Step 2 運行應用,採集信息

 

1.3 CW 主界面,點擊執行程序,正常進行操作,CW自動採集EXE執行期間的event。

 

 

Step 3 結束exe, 查看採集的信息

 

3.1 正常退出exe,CW彈出初步結果, 這裏可以看到在剛纔的運行期間中該DLL發生了3次未預計的操作系統資源泄漏 、1次捕獲的內存泄漏

 

 

3.2 這裏可以看到3次的資源泄漏其實是-1個window未關閉、1個process handle、1個ThreadHandle未關閉。窗口泄漏的根源發現是在某個單元中創建TTimer未釋放,VCL的TTimer其實就是開個窗口接 收WM_TIMER,暫且不表。

 

 

 

3.3 泄漏時的線程棧表明發生在 uExtractor1.pas 181行處,代碼片斷如下。 此處創建了一個額外的工作exe,如果該工作exe在規定時間內正常退出則會關閉該工作exe的進程、線程句柄;但是如果超時了,會調用另一個公共函數 KillProc 殺掉該exe及其子孫進程,這裏範了錯誤,在殺掉後沒有關閉該exe的句柄。

 

  bCreateProcess := CreateProcess(nil, PChar(sCommand), nil, nil, True, CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS, nil, nil, lpStartupInfo, lpProcessInformation); if bCreateProcess then begin case WaitForSingleObject(lpProcessInformation.hProcess, WaitForSec * 1000) of WAIT_TIMEOUT: begin Result:= 4; KillProc(lpProcessInformation.dwProcessId, True, Result); end; WAIT_OBJECT_0: begin GetExitCodeProcess(lpProcessInformation.hProcess, ResultCode); CloseHandle(lpProcessInformation.hProcess); CloseHandle(lpProcessInformation.hThread); Result := ResultCode; end; end; end else Result := 9;

 

3.4 修改代碼即使KillProc 也要關閉 hProcess hThread。 OK! 泄漏問題解決

 

 

總結:

 

1. Dll 的代碼一定要謹慎編寫,因爲申請的系統資源都是隸屬於主調exe的,主調exe不退出,中間泄漏的資源操作系統都沒辦法幫你自動回收;

 

2. CreateProcess後打開的進程句柄一定要釋放,即使該程序被另外的地方殺掉了,因爲只要一處打開的句柄不關閉,操作系統爲該進程維護的內核對象的句柄計數都不會減到0,導致泄漏

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章