使用UMDH分析查找内存泄漏技术
上半年对内存泄漏查找作了一个总结,主要是使用crt的debug版本查找内存泄漏,但是存在的缺陷是只能定位到用户代码中自己分配的内存,对于使用其他库中分配的内存,应用程序没有释放的这种泄漏定位还是非常困难。本文介绍使用windbg工具中的UMDH来分析查找内存泄漏可以方便的定位到内存分配的堆栈,即使是在第三方库中分配的内存没有释放,也可以追溯到调用堆栈,方便定位泄漏原因。
1. UMDH安装
UMDH是Debuging tools for windows(x86)的一个工具,要使用UMDH需要先安装 Debuging tools for windows(x86),该软件在微软官方网站可以免费下载到。
2. UMDH介绍
UMDH的英文全称是User-Mode Dump heap tool.Umdh.exe用来分析指定进程windows堆内存分配记录。UMDH有两种模式。
分析运行中的进程(“Mode1”). UMDH捕获和分析指定运行进程的堆内存分配情况。对于每一次内存分配,UMDH显示这次分配的内存大小,使用的大小,内存分配的指针以及内存分配的堆栈。如果一个进程有多个活动的内存堆,UMDH捕获所有的堆。
分析UMDH日志文件(“Mode2”). UMDH分析其捕获日志帮助程序员分析定位内存泄漏。当UMDH比较两次的捕获日志,UMDH显示某个调用堆栈分配内存增长的字节数,以及运行的次数。
3. UMDH的使用准备
设置Create user mode stack trace database
使用UMDH前必须先为指定的进程设置Create user mode stack trace database标志。
使用GFlags工具为进程设置Create user mode stack trace database标志激活栈跟踪功能。该工具使用方式如下,需要再进程启动之前。 Glags /i 进程文件名 +ust
设置环境变量
set _NT_SYMBOL_PATH=c:\mysymbols;srv*c:\mycache*http://msdl.microsoft.com/download/symbols
其中c:\mysymbols是用户程序符合文件目录,当然可以改成你的程序的符合文件位置
第一次捕获进程内存分配情况
当做好上诉准备工作后,就可以开始进行内存分配情况捕获了。
Umdh –p:ProcessId –f:log1.txt
第二次捕获进程内存分配情况
在程序运行一段时间后,在发现内存已经上涨了后进行第二次捕获。
Umdh –p:ProcessId –f:log2.txt
比较日志
现在两个日志文件都分别记录两次捕获时的内存分配情况,需要使用UMDH来比较下两个文件,得出这两次捕获之间内存分配的增长情况。
Umdh log1.txt log2.txt > logcompare.txt
比较结果就保存到logcompare.txt文件中去了,打开该文件分析查找内存泄漏情况。
日志分析
1. 打开logcompare.txt文件后,可以看到类似下面的这段描述。
+ 5320 ( f110 - 9df0) 3a allocs BackTrace00B53
Total increase == 5320
在UMDH 日志文件中对于每个堆栈(标志BackTrace),在两次的捕获中都有一个对比结果。比如在这个例子中,第一个文件log1.txt记录0x9DF0个字节被
BackTrace00B53分配,而在第二个文件中这个栈分配了0XF110个字节,这就说明0X5320个字节被泄漏了。这些个字节的是被堆栈BackTrace泄漏掉的。
2. 那么Backtrace00B53到底是什么呢?打开其中任何一个文件都可以看到整个 调用堆栈了,比如我们打开log2.txt,搜索下BackTrace00B53,搜索结果如下: 00005320 bytes in 0x14 allocations (@ 0x00000428) by: BackTrace00B53
ntdll!RtlDebugAllocateHeap+0x000000FD
ntdll!RtlAllocateHeapSlowly+0x0000005A
ntdll!RtlAllocateHeap+0x00000808
MyApp!_heap_alloc_base+0x00000069
MyApp!_heap_alloc_dbg+0x000001A2
MyApp!_nh_malloc_dbg+0x00000023
MyApp!_nh_malloc+0x00000016
MyApp!operator new+0x0000000E
MyApp!DisplayMyGraphics+0x0000001E
MyApp!main+0x0000002C
MyApp!mainCRTStartup+0x000000FC
KERNEL32!BaseProcessStart+0x0000003D
至此,我们发现了原来是MyApp中DisplayMyGraphics函数中调用的new有泄漏。仔细检查源代码,看看在哪忘记了delete吧。