开发者社区> nothingfinal> 正文

句柄泄漏调试经验

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

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

句柄泄漏检测-更多信息
任务管理器只能简单检测句柄数,如果要获得更详细的信息,可以使用Process Explorer(官方下载地址为http://technet.microsoft.com/en-us/sysinternals/bb896653.aspx)通过Process Explorer可以查看进程句柄的类型和名字,如图所示:
通过任务管理器和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就使用了这样了的策略。


http://www.programlife.net/handle-leak-debug-skill.html

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
阿里云服务器端口号设置
阿里云服务器初级使用者可能面临的问题之一. 使用tomcat或者其他服务器软件设置端口号后,比如 一些不是默认的, mysql的 3306, mssql的1433,有时候打不开网页, 原因是没有在ecs安全组去设置这个端口号. 解决: 点击ecs下网络和安全下的安全组 在弹出的安全组中,如果没有就新建安全组,然后点击配置规则 最后如上图点击添加...或快速创建.   have fun!  将编程看作是一门艺术,而不单单是个技术。
18998 0
阿里云服务器ECS登录用户名是什么?系统不同默认账号也不同
阿里云服务器Windows系统默认用户名administrator,Linux镜像服务器用户名root
13953 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,阿里云优惠总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系.
25240 0
阿里云服务器怎么设置密码?怎么停机?怎么重启服务器?
如果在创建实例时没有设置密码,或者密码丢失,您可以在控制台上重新设置实例的登录密码。本文仅描述如何在 ECS 管理控制台上修改实例登录密码。
20697 0
使用SSH远程登录阿里云ECS服务器
远程连接服务器以及配置环境
13981 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,大概有三种登录方式:
10016 0
腾讯云服务器 设置ngxin + fastdfs +tomcat 开机自启动
在tomcat中新建一个可以启动的 .sh 脚本文件 /usr/local/tomcat7/bin/ export JAVA_HOME=/usr/local/java/jdk7 export PATH=$JAVA_HOME/bin/:$PATH export CLASSPATH=.
14117 0
阿里云ECS云服务器初始化设置教程方法
阿里云ECS云服务器初始化是指将云服务器系统恢复到最初状态的过程,阿里云的服务器初始化是通过更换系统盘来实现的,是免费的,阿里云百科网分享服务器初始化教程: 服务器初始化教程方法 本文的服务器初始化是指将ECS云服务器系统恢复到最初状态,服务器中的数据也会被清空,所以初始化之前一定要先备份好。
14744 0
+关注
nothingfinal
软件开发,安全加密
1069
文章
341
问答
文章排行榜
最热
最新
相关电子书
更多
JS零基础入门教程(上册)
立即下载
性能优化方法论
立即下载
手把手学习日志服务SLS,云启实验室实战指南
立即下载