1.简介
umdh是windows debug tools下的一款命令行工具,它的全名是User-Mode Dump Heap 这个工具会分析当前进程在堆上分配的内存,通过命令操作,可以对当前进程分配的每一块内存做日志记录,其中包含分配的内存大小、内存分配地址、内存分配时的函数调用堆栈等;还可以通多命令操作,比较几个顺序时间的日志记录,找出内存增长的位置。
2.步骤
在已经安装windbg的情况下,使用umdh排查内存增长问题的步骤如下:
1) 配置系统 环境变量设置
变量名:_NT_SYMBOL_PATH
变量值:SRV*C:\Windows\symbols*http://msdl.microsoft.com/download/symbols;E:\pdb
(windbg加载pdb的路径)
注意:E:\pdb指加载调试程序的pdb文件路径,如果有多个路径可以用‘;’分开添加;C:\Windows\symbols指向windows系统自己的pdb文件,windows系统的pdb文件在调试的时候其会自动从windows官网上下载。
设置环境变量后VS在启动程序时会自动加载_NT_SYMBOL_PATH下的pdb文件,会使调试程序较慢,所以在不需要时,建议把它去掉。
2)开启cmd
以管理员身份运行cmd,并进入windbg存在的路径下,如:
cd C:\Program Files\Debugging Tools for Windows (x64)
注意:windbg和程序的位数要一致,这里是64位的;
3)创建用户态堆栈追踪数据库
gflags -i appname.exe(目标进程名称) +ust
4)利用umdh创建heap快照
umdh -p:目标进程 ID -f:E:\umdh\log1.txt(输出日志文件)
或者
umdh -pn:appname.exe(目标进程名称) -f:E:\umdh\log1.txt(输出日志文件)
程序运行一段时间后,再次创建heap快照,命令无差别,log1.txt改为log2.txt;
5)比较分析heap前后两个快照的差异
umdh -d E:\umdh\log1.txt E:\umdh\log2.txt > E:\umdh\cmp12.txt
3.Demo分析内存泄漏
【demo代码】
int main()
{
for (int i = 0; i < 10000; i++)
{
char *p = new char[10240];
memset(p, 0, 10240);
Sleep(100);
}
}
Release32编译生成程序名称为demo.exe,demo.exe与demo.pdb路径为E:\umdh\release;
1)配置环境变量
值为:SRV*C:\Windows\symbols*http://msdl.microsoft.com/download/symbols;E:\umdh\release
2)开启cmd
进入32位的windbg路径下,如:
cd C:\Program Files (x86)\Windows Kits\8.1\Debuggers\x86
3)运行demo.exe
只要在创建用户态堆栈追踪数据库之前运行程序就OK;通过任务管理器可以明显看到内存持续增长;
4)创建用户态堆栈追踪数据库
gflags -i demo.exe +ust
5)利用umdh创建heap快照
umdh -pn:demo.exe -f:E:\umdh\demo_log1.txt
等待一会时间后再次创建heap快照:
umdh -pn: demo.exe -f:E:\umdh\demo_log2.txt
6)比较分析heap前后两个快照的差异
umdh -d E:\umdh\demo_log1.txt E:\umdh\demo_log2.txt > E:\umdh\demo_cmp12.txt
执行该命令需要等待一段时间,应该是在加载pdb文件;
7)分析对比结果
执行完上述流程后吗,可以在E:\umdh路径下看到demo_log1.txt、demo_log2.txt、demo_cmp12.txt三个日志文件;现在分析对比结果demo_cmp12.txt文件,如下图:
对比文件从上到下展示了符号文件加载信息,具体内存泄露信息、总的内存增长信息;
具体的内存泄漏信息格式说明:
第一行:+ 4833280 ( 5765120 - 931840) 563 allocs BackTrace2D2ED8
BackTrace2D2ED8是这个内存块的标,5765120是生成demo_log2.txt时该内存块的大小,931840是生成demo_log1.txt该内存块的大小,差值+4833280是指在这两个日志文件时间差内,内存分配的增长的字节数,563 是分配内存的次数;
第二行:+ 472 ( 563 - 91) BackTrace2D2ED8 allocations
BackTrace2D2ED8是内存块标记和第一行一样,563是生成demo_log2.txt时该内存分配的次数,91是生成demo_log1.txt时该内存分配的次数,差值472是在这两个日志文件时间差内,该内存块分配的次数。
其他行:是函数调用堆栈,通过分析程序发现,下面这三行
MSVCR120!malloc+49 (f:\dd\vctools\crt\crtw32\heap\malloc.c, 92)
MSVCR120!operator new+1D (f:\dd\vctools\crt\crtw32\heap\new.cpp, 59)
demo!main+15(d:\program\vs2013\test3\test3\main.cpp, 9)
很明显的指明了内存泄漏的位置,是因为调用了new分配内存,具体位置是\main.cpp文件中的第9行附近。
上述图中具体的内存泄漏信息中,只显示了一个内存分配追踪的动作,堆栈调用部分的最上面几行是系统内核最终调用分配函数。