原创,欢迎转载,请注明出处
前言
最近在Windows平台上扩展ovs-vswitchd的功能时,遇到了内存泄漏的问题。查阅windbg的文档,使用UMDH工具解决。特此记录一下。
本文使用的工具随EWDK_rs3_release_16299_170928-1534开发套件发行,VS是否带有该工具请自行查阅。本文提及的工具在EWDK的安装目录的“Program Files\Windows Kits\10\Debuggers\x64\”文件夹中。本文的操作都是在控制台下执行的。默认系统的PATH变量中不包含这些命令所在的目录,请自行添加或执行命令时输入全路径。
准备
创建用户空间程序栈跟踪数据库(Create user mode stack trace database)
使用gflags命令设置,命令格式如下:1
"{EWDK安装目录}\Program Files\Windows Kits\10\Debuggers\x64\gflags" /i ImageName +ust
注意:ImageName是指被检测的程序的名称,包含扩展名。例如:glags /i main.exe +ust.
设置环境变量_NT_SYMBOL_PATH
Windows调试工具(WinDbg, KD, CDB, NTST)通过_NT_SYMBOL_PATH查找程序的符号表。在控制台下设置该变量的语法如下:1
set _NT_SYMBOL_PATH=c:\myapp\symbols;srv*c:\mycache*https://msdl.microsoft.com/download/symbols
- 命令中的“c:\myapp\symbols”的路径中包含被检测的文件的pdb文件。
- set命令设置环境变量的作用范围是当前的console会话。如需,该环境变量永久有效,请使用setx命令。
UMDH使用
使用UMDH收集程序的运行时信息
命令语法如下:
1 | "{EWDK安装目录}\Program Files\Windows Kits\10\Debuggers\x64\umdh.exe" -p:{程序的PID} -f:log0 |
通常UMDH命令会被执行至少两次。注意日志请使用不同的名字。
使用UMDH分析程序运行时行为
命令语法:
1 | "{EWDK安装目录}\Program Files\Windows Kits\10\Debuggers\x64\umdh.exe" log0 log1 |
接下来通过一个例子看一下UMDH能给我们什么样的信息。
示例
创建一个内存泄漏程序
- 程序代码如下
1 |
|
- 编译程序的命令如下,生成的程序名为main.exe
1 | cl /EHsc /Zi main.c |
注意编译时私用/Zi开关,生成pdb文件。该文件在分析程序行为时,被用于定位具体的代码行。
/Z7
编译时,生成.obj文件,其包含可被调试工具使用的符号信息。/Zi
生成程序数据文件(PDB),该文件包含可被调试工具使用的类型信息和符号信息。/ZI
与/Zi开关的作用相似,生成PDB文件。不同的是,PDB文件的格式不同。此PDB文件支持“Edit”和“Continue”。
准备工作
- 创建main.exe的栈跟踪数据库
1 | glags /i main.exe +ust |
- 设置_NT_SYMBOL_PATH环境变量
1 | set _NT_SYMBOL_PATH=e:\workspace\test;srv*c:\mycache*https://msdl.microsoft.com/download/symbols |
“e:\workspace\test”目录下包含main.pdb文件
收集数据
- 运行main.exe
1 | main.exe |
- 使用UMDH收集运行时行为
在控制台下运行下面的命令,收集main.exe的运行时行为,记录存储到“log0”文件中
1 | umdh.exe -p:2230 -f:log0 |
几秒钟后,再次运行umdh收集程序行为信息,记录存储到“log1”文件中
1 | umdh.exe -p:2230 -f:log1 |
分析数据
- 命令如下
1 | umdh.exe -v log1 log0 |
命令的输出结果如下:
1 | - 988 ( 1600 - 1f88) 580 allocs BackTrace94D0588E |
输出结果中的第七行指出了内存泄漏发生的位置。如果程序中不知一处有内存泄漏,则umdh会输出每一个发生内存泄漏的代码行。
后记 - “一个空格引发的血案”
写作过程中,由于块代码(block code)使用“```”标识的。由于块代码的结束标记“```”多了一个空格导致格式始终显示不对。预期的结果是这样:
1 | aaa |
1 | bbb |
多余的空格导致显示如下:
1 | aaa |
经验不足,这个问题花了较长的时间才解决。