句柄泄漏调试经验
句柄泄漏檢測-簡單
在調試之前首先確定是不是真的發生了句柄泄漏,簡單的檢測方法是通過任務管理器來查看進程的句柄數是不是居高不下,任務管理器默認不顯示句柄數,要查看進程的句柄數需要先切換到進程選項卡,然后單擊“查看”菜單,選擇“選擇列”,然后勾選“句柄數”。
句柄泄漏檢測-更多信息
任務管理器只能簡單檢測句柄數,如果要獲得更詳細的信息,可以使用Process Explorer(官方下載地址為http://technet.microsoft.com/en-us/sysinternals/bb896653.aspx)通過Process Explorer可以查看進程句柄的類型和名字,如圖所示:
可以通過這些詳細信息來初步判斷那個地方出了問題。
句柄泄漏檢測和調試
Windbg提供了強大的擴展命令!htrace,即句柄跟蹤(Handle Trace),可以通過操作系統來跟蹤所有打開句柄或關閉句柄的調用以及相應的棧回溯。
在命令行下啟動目標程序(源碼下載),讓后將Windbg附加到這個進程上,在Windbg輸入”!htrace -?”,可以查看命令幫助。
我們需要先在Windbg中輸入”!htrace -enable”來開啟棧回溯,然后通過g命令來運行被調試的程序,等到程序運行結束時,再在Windbg中運行”!htrace”來觀察和打開或關閉句柄有關的棧回溯信息,Windbg的調試日志如下:
| // 發現部分RSS訂閱工具顯示代碼的格式很混亂 // RSS訂閱讀者可以通過閱讀原文正常查看代碼或者更換訂閱工具 0:001> !trace -? No export trace found 0:001> !htrace -? !htrace [handle [max_traces]] !htrace -enable [max_traces] !htrace -disable !htrace -snapshot !htrace -diff 0:001> !htrace -enable Handle tracing enabled. Handle tracing information snapshot successfully taken. 0:001> g (130c.1558): Break instruction exception - code 80000003 (first chance) eax=7ffde000 ebx=00000000 ecx=00000000 edx=772bd23d esi=00000000 edi=00000000 eip=77253540 esp=006ff8d0 ebp=006ff8fc iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 ntdll!DbgBreakPoint: 77253540 cc int 3 0:001> !htrace -------------------------------------- Handle = 0x00000080 - CLOSE Thread ID = 0x000017dc, Process ID = 0x0000130c0x7726491c: ntdll!ZwClose+0x0000000c 0x75476b1c: KERNELBASE!CloseHandle+0x0000002d 0x76c2057f: kernel32!CloseHandleImplementation+0x0000003f *** WARNING: Unable to verify checksum for G:\W7Documents\Visual Studio 6.0\Projects\HLeak\Debug\HLeak.exe 0x01201afb: HLeak!wmain+0x0000032b 0x01202b68: HLeak!__tmainCRTStartup+0x000001a8 0x012029af: HLeak!wmainCRTStartup+0x0000000f 0x76c21114: kernel32!BaseThreadInitThunk+0x0000000e 0x7727b3f5: ntdll!__RtlUserThreadStart+0x00000070 0x7727b3c8: ntdll!_RtlUserThreadStart+0x0000001b -------------------------------------- ……省略N多行信息…… -------------------------------------- Handle = 0x00000030 - OPEN Thread ID = 0x000017dc, Process ID = 0x0000130c0x77264b7c: ntdll!NtCreateThreadEx+0x0000000c 0x7547bd01: KERNELBASE!CreateRemoteThreadEx+0x00000161 0x76c227bd: kernel32!CreateThreadStub+0x00000020 0x01201a5a: HLeak!wmain+0x0000028a 0x01202b68: HLeak!__tmainCRTStartup+0x000001a8 0x012029af: HLeak!wmainCRTStartup+0x0000000f 0x76c21114: kernel32!BaseThreadInitThunk+0x0000000e 0x7727b3f5: ntdll!__RtlUserThreadStart+0x00000070 0x7727b3c8: ntdll!_RtlUserThreadStart+0x0000001b-------------------------------------- Parsed 0x158 stack traces. Dumped 0x158 stack traces. |
如何調試?
看起來輸出信息過多,如果要一個一個去看哪些句柄沒有CLOSE,那樣工作量太大了。我們可以通過在Windbg中輸入”!htrace -diff”來自動篩選出沒有CLOSE的句柄的棧回溯信息:
| 0:001> !htrace -diff Handle tracing information snapshot successfully taken. 0x158 new stack traces since the previous snapshot. Ignoring handles that were already closed... Outstanding handles opened since the previous snapshot: -------------------------------------- Handle = 0x000003a4 - OPEN Thread ID = 0x000012bc, Process ID = 0x0000130c0x772651ec: ntdll!ZwOpenProcessToken+0x0000000c 0x7547748f: KERNELBASE!OpenProcessToken+0x00000014 0x0120237e: HLeak!CServer::GetToken+0x0000007e 0x01201da9: HLeak!CServer::GetSID+0x00000039 0x012015d3: HLeak!ThreadWorker+0x000000c3 0x76c21114: kernel32!BaseThreadInitThunk+0x0000000e 0x7727b3f5: ntdll!__RtlUserThreadStart+0x00000070 0x7727b3c8: ntdll!_RtlUserThreadStart+0x0000001b -------------------------------------- ……省略N多行信息…… -------------------------------------- Handle = 0x0000003c - OPEN Thread ID = 0x0000168c, Process ID = 0x0000130c0x772649fc: ntdll!NtCreateEvent+0x0000000c 0x772495d7: ntdll!RtlpCreateCriticalSectionSem+0x0000001a 0x772495ad: ntdll!RtlpWaitOnCriticalSection+0x00000074 0x7724fb56: ntdll!RtlEnterCriticalSection+0x00000150 0x7727b479: ntdll!LdrpInitializeThread+0x000000c6 0x7727b298: ntdll!_LdrpInitialize+0x000001ad 0x7727b2c5: ntdll!LdrInitializeThunk+0x00000010 -------------------------------------- Displayed 0x68 stack traces for outstanding handles opened since the previous snapshot. |
可以通過這些信息來幫助對句柄泄漏的調試過程。
句柄泄漏回避策略
使用RAII(Resource Acquisition Is Initialization)策略,這個就不多說了,STL里面的auto_ptr就使用了這樣了的策略。
http://www.programlife.net/handle-leak-debug-skill.html
總結
- 上一篇: LeetCode 28_Implemen
- 下一篇: 51nod 1766