句柄泄漏调试经验

句柄泄漏检测-简单
在调试之前首先确定是不是真的发生了句柄泄漏,简单的检测方法是通过任务管理器来查看进程的句柄数是不是居高不下,任务管理器默认不显示句柄数,要查看进程的句柄数需要先切换到进程选项卡,然后单击“查看”菜单,选择“选择列”,然后勾选“句柄数”。

句柄泄漏检测-更多信息
任务管理器只能简单检测句柄数,如果要获得更详细的信息,可以使用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 = 0x0000130c
 
0x7726491c: 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 = 0x0000130c
 
0x77264b7c: 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 = 0x0000130c
 
0x772651ec: 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 = 0x0000130c
 
0x772649fc: 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就使用了这样了的策略。


Copyed From 程序人生
Home Page:http://www.programlife.net
Source URL:http://www.programlife.net/handle-leak-debug-skill.html

你可能感兴趣的:(句柄泄漏调试经验)