文章目录
一、观察进程是否有句柄泄漏
1、查看工具
使用任务管理器或Process Explorer(procexp.exe)工具可观察进程的句柄数。
任务管理器查看句柄数
procexp.exe查看进程句柄信息
2、判断是否有句柄泄漏
通常在程序运行稳定后,再观察句柄数有无增长,比如进程启动5分钟后再开始观察,让其运行半天或一天,比较前后的句柄数有无明显增长。
可以使用性能监视工具或者在Procexp.exe选中进程,点击菜单中的保存可以存成txt文本查看,可以通过比较前后两次的txt查看哪些句柄有泄漏。
二、定位方法
1、WinDbg分析句柄泄漏
1.1 Event句柄泄漏
1.1.1 代码示例
#include "stdafx.h"
#include <ctime>
void HandleLeak()
{
for (int i = 0; ; i++)
{
CreateEvent(NULL, true, false, NULL);
Sleep(10000);
}
}
int _tmain(int argc, _TCHAR* argv[])
{
HandleLeak();
system("pause");
return 0;
}
生成文件名为testC.exe
1.1.2
1)打开WinDbg,设置好pdb路径以及源码路径
2)打开exe
3)在WinDbg命令窗口中执行g
回车换行,进程启动了
4)过一会后,点击WinDbg菜单栏的Break或者按下Ctrl+Break
5)此时分别执行以下命令
!htrace -enable:启用handle trace,并且创建第一个快照作为初始状态,方便使用 -diff选项
!htrace:显示当前的所有句柄信息
!htrace -snapshot:创建快照,用作-diff选项
执行一下g命令,同3)
6)过一会后,break掉,同4),在WinDbg命令窗口执行
!htrace -diff:使用当前状态的信息,和最近一次的快照信息做对比
由图可知,和快照做对比,发现比快照多了7个handle
7)根据6)中的handle值,执行
!handle xxx f:查看一下handle的信息
从这里可以知道这个handle的类型是event
8)在有源码和pdb的情况下,可以使用 lsa命令定位到源码所在位置,如
lsa KERNELBASE!CreateEventExW+0x0000000000000056
当然这里因为是windows内部的模块,没有加pdb和源码,因此不会显示到对应行
9)根据7),我们看不见是我们那一行代码导致的问题,因此可以反汇编获取函数的返回地址,如下:
我们找到返回地址,图中箭头位置,拿到7713a02a
10)调试一下断点
.logappend /u e:/test.log:表示将此命令的结果Append到e:/test.log文件中,/u表示 in Unicode format。
k :表示输出栈信息
r eax:表示输出eax寄存器的值,即取函数的返回值
.logclose:表示关闭日志记录
g:表示命中断点后继续执行
11)打开test.log
由日志去查看源代码,发现CreateEvent后没有close的操作,到此就定位出了Event句柄泄漏的位置。
备注:当我们从文件得知可能出现句柄泄漏的句柄时,我们可以用windbg挂对应的进程,等对应的进程或目录或其他名称出现,这个时候用procexp看对应句柄值,再在windbg执行!htrace -diff的内容中查找对应的句柄值。