转载自:http://blog.csdn.net/whatday/article/details/47301145
A.利用工具umdh(user-mode dump heap)分析
Gflags标志设置好后,开启cmd
键入要定位内存泄露的程序gflags.exe /i memroyleak.exe +ust
如图成功后,开启memoryleak.exe程序
命令格式:umdh -pn:memoryleak.exe -f:snap1.log
程序运行一段时间后或者程序占用内存增加时,然后再次创建heap快照,命令行无差别,snap1.log改为snap2.log或者其他。
设置好程序的符号路径,如下图
设置好后可以开始分析heap前后两个快照的差异
分析差异命令:umdh -d snap1.log snap2.log -f:result.txt
生成的result.txt文件在 命令行同目录下 这里是 D:\WinDDK\7600.16385.0\Debuggers
分析完成后查看结果result.txt
红色为umdh定位出来的泄露点,我们在查看源代码
这样我们就可以修改代码中内存泄露的地方了。
内存泄露实例分析:
两次快照差异文件实例大致如下:
第一行:+ 47e0 ( 237238 - 232a58) 1f9 allocs BackTrace8E5CFAC
BackTrace8E5CFAC是这个内存块的标记 237238是生成日志文件2时该内存块的大小 232a58是生成日志文件1该内存块的大小 差值47e0 是内存泄露的字节数 1f9是分配内存的次数 (其中47e0 个人理解为申请内存未释放的字节数,因为有可能是释放的时间未到就生成日志文件2 造成只有申请内存 没有释放的情况 所以被判定为内存泄露 关于这点只是个人意见 不一定正确) 。
第二行:+ 4 ( 1f9 - 1f5) BackTrace8E5CFAC allocations
BackTrace8E5CFAC是内存块标记和第一行一样,1f9是生成日志文件2时该内存分配的次数, 1f5是生成日志文件1时该内存分配的次数 差值4是这次该内存块分配的次数。
其他行:是函数调用堆栈,通过分析自己的程序发现,第三行的 Server!CUi::AddItemText+129 (d:\projects\testtest\common\uilibf, 611) 也是内存泄露所在,对应源代码是:pItemLabel = new CLabelUI; 这样基本上就定位到问题所在了
验证一下观点:每一次分配的大小是47e0 /4=4600(十进制), 程序中代码验证了sizeof(CLabelUI)也等于4600, 看来从日志1 到日志2 过程中这个地方new了4次 但是在日志2时 还未释放这些内存 所以造成内存比较时 会定位处该块内存的泄露,至于是否真泄露还是要看程序逻辑,但是既然已定位到该代码 还是要仔细分析一下 看看是逻辑问题 还是真忘了释放内存。
开启memoryleak.exe程序,windbg attach到该进程
命令:!heap –s查看当前进程运行的所有堆的情况
然后F5让程序运行一段时间或者内存有明显的增加时再次通过!heap –s查看当前堆的变化
如下图
通过对比前后两个堆的变化,发现0x012800000该地址的堆增加的很快而其他堆没什么变化
下面进一步定位
命令:!heap –stat –h 查看对应对的状态,发下该堆的内存基本被长度为0x424的块占用,接下来我们在堆中搜索该进程中哪些模块占用0x424长度内存,如下图
命令:!heap –flt s 424
通过搜索程序内存中的堆发现长度为424的堆被大量的占用,进一步查看时谁在使用这个地址
找到泄露点了,红色部分的,如果程序对应的符号对应我们可以查看内存泄露点在哪一行
内存泄露分析结束,如果你还有什么好的方法可以共享