使用WinDbg来跟踪内存泄漏是一个强大且复杂的任务,因为它涉及到对Windows内存管理机制的深入理解,以及对WinDbg调试工具的熟练使用。以下是一个基本的步骤指南,用于通过WinDbg来检测和跟踪内存泄漏:
两种方式:
windbggflagsexeumdhexe_3">一、通过windbg辅助工具gflags.exe和umdh.exe
需要使用windbgs的安装目录下的gflags.exe和umdh.exe完成从内存检测,下面的命令需要以管理员权限运行cmd命令行窗口程序,并切换到windbg目录。
1、管理员权限启动cmd命令;
2、进入到Debugging Tools for Windows (x86)目录:cd C:\Program Files (x86)\Debugging Tools for Windows (x86)
1、设置pdb符号路径
umdh分析出使用堆内存的函数调用堆栈,为方便查看看函数调用堆栈中的具体函数,可以先设置符号的pdb文件路径,设置的变量名称必须为: _NT_SYMBOL_PATH,设置后需要重启电脑。
不设置会报如下错误:
Warning: _NT_SYMBOL_PATH variable is not defined. Will be set to %windir%\symbols.
1)、通过系统设置:
2)、通过cmd命令设置:
#设置符号路径
set _NT_SYMBOL_PATH="c:\Symbols\;SRV*c:\Symbols\*http://msdl.microsoft.com/download/symbols"
3、启动应用程序
确保你的应用程序在调试模式下编译,并且包含了完整的调试信息(PDB文件)。
gflagsexe_32">4、使用gflags.exe设置要监控内存状态的进程
glags也在Debugging Tools for Windows (x86)目录下,和windbg同步目录,下面以监控test.exe为例:
umdhexe_35">5、使用umdh.exe获取进程的内存数据和堆栈变化结果。
umdh也在Debugging Tools for Windows (x86)目录下,和windbg同步目录。
1)、启动cmd命令;
2)、进入到Debugging Tools for Windows (x86)目录:cd C:\Program Files (x86)\Debugging Tools for Windows (x86)
3)、查看进程某一时刻的内存状态,并保存下来:umdh.exe -p:21564 -f:D:/aaa.txt
,其中-p后面是进程的PID,-f后接的是文件保存路径
4)、间隔一段时间,重复步骤3),但保存文件名记得修改:
umdh.exe -p:21564 -f:D:/bbb.txt
umdh.exe -p:21564 -f:D:/ccc.txt
5)、比较两个内存数据的状态,找到两个时刻的变化,并将比较结果保存到reslut.txt中。
umdh.exe D:/aaa.txt D:/bbb.txt -f:D/:reslut.txt
6)、查看分析结果
比较aaa.txt和bbb.txt两个文件中堆内存的使用变化量,得出统计数据保存到reslut.txt中,即可查看到堆内存的变化情况,按堆内存的数量从高到低排列,而且有详细的函数的调用堆栈,分析使用量较高的几项即可
抓取第一次堆内存快照后,间隔了比较长的时间,抓取了第二次。23fbeb0 ( 2409090 - d1e0) 240909 allocs BackTrace6A 23fbeb ( 240909 - d1e) BackTrace6A allocations
格式说明:
23fbeb0 : 表示两次内存快照之间,增加的内存,
2409090:第二次使用内存快照时该堆占用内存,
d1e0:第一次使用内存快照时该堆占用的内存
240909:总的分配次数
23fbeb:两次之间,多分配的次数
240909:第二次内存快照到第一次之间分配次数
d1e:第一次的内存快照分配的次数
0x23fbeb0/0x23fbeb = 0x10 刚好16个字节,符合我们前面分析的内存泄露的字节大小,
从调用堆栈上看,内存泄露的地方像是在使用标准的std::string 中发生的,根据调用堆栈提示的代码行数,找到对应的代码部分。
windbg_67">二、通过windbg附加进程方式
使用 Windbg 来跟踪内存泄漏是一个强大的方法,特别是针对 Windows 应用程序。Windbg 是 Microsoft 提供的强大的调试工具,它不仅可以用来调试崩溃问题,还可以用来分析内存泄漏等性能问题。
1. 准备环境
- 确保你的应用程序有调试符号(PDB 文件)。这些文件包含了源代码和二进制之间的映射,使得调试器能够显示源代码行号等信息。
- 安装并配置 Windbg。
- 设置符号路径,设置方式可以跟前文中提到的设置环境变量方式,也可以如下图,加入pdb所在目录。
- 设置源文件所在路径
2. 附加到进程
- 启动你的应用程序。
- 打开 Windbg,并使用
File > Attach to a Process
菜单项附加到正在运行的应用程序进程。
3. 设置断点(可选)
- 如果你知道内存泄漏可能发生在代码的特定部分,你可以设置断点来暂停执行。使用
bp <模块名>!<函数名>
命令来设置断点。
4. 使用扩展命令分析内存
Windbg 提供了多个扩展命令来帮助分析内存,其中 .dmp
命令用于创建内存转储,而 !heap
、!analyze -v
、!eeheap -gc
(对于托管代码)等命令则用于分析内存状态。
-
对于非托管代码:
- 使用
!heap -s
查看堆的摘要信息。 - 使用
!heap -stat
查看堆上对象的统计信息。 - 使用
!heap -l
列出堆上的所有分配。 - 使用
!heap -p -a <地址>
查看特定内存地址的详细信息。
- 使用
-
对于托管代码(.NET 应用程序):
5. 监视内存变化
- 在应用程序运行期间,定期使用上述命令来监视内存的变化。
- 特别注意那些数量不断增加的对象类型,它们可能是内存泄漏的源头。
6. 深入分析
- 如果发现可疑的对象或内存区域,使用 Windbg 的其他命令或扩展来进一步分析。
- 你可以使用
!dso
、!clrstack
等命令来查看调用栈,了解对象是如何被创建和引用的。
7. 解决问题
- 根据分析结果,修改代码以修复内存泄漏。
- 重复上述步骤以验证问题是否已解决。
8. 记录和文档
- 记录你的发现、分析和解决方案,以便将来参考。
使用 Windbg 跟踪内存泄漏需要一定的学习和实践,但一旦你掌握了它,它将是一个非常强大的工具,可以帮助你解决复杂的内存问题。
注意事项
通过遵循上述步骤,你可以使用WinDbg来有效地跟踪和修复内存泄漏问题。不过,这需要对WinDbg及其扩展工具的深入了解和大量的实践。