LeakDiag – 有效的内存泄漏分析工具






4.56/5 (6投票s)
用于检测 C++ 应用程序中内存泄漏的工具
引言
当代码库庞大而复杂时,内存泄漏问题会变得相对复杂和棘手,如果应用程序在服务器上运行数天,问题会更加严重。由于这是 C++ 代码中一个非常常见的问题,因此开发了许多用于分析内存泄漏的工具,例如 Rational Purifier、Bounds Checker,但这些工具并非免费提供。如果您想在不投资这些工具的情况下查找程序中的内存泄漏,请继续阅读本文。
在哪里可以获取此工具?
这是 Microsoft 开发和分发的一个工具,可在 Microsoft 的 FTP 上免费获得:ftp://ftp.microsoft.com/PSS/Tools/Developer%20Support%20Tools/LeakDiag/。下载并在此应用程序运行的系统上安装此工具。(这可能是您的桌面或服务器计算机。)
LeakDiag 是什么?
这是一款免费软件,用于检测大中型企业应用程序的内存泄漏,使用起来非常简单方便。我们可以使用此工具查找简单的 EXE 文件和 Windows 服务内存泄漏;好的一点是,我无需停止应用程序即可开始泄漏分析。此工具的输出是一个 XML 文件,其中包含在快照时已分配但未释放的所有堆栈帧。我们将在下面详细介绍此过程。在实际开始收集日志之前,我们需要进行一些初始设置。
初始设置
我们需要做的第一件事是设置公共符号路径(srv*c:\symcache*http://msdl.microsoft.com/download/symbols)。打开工具,然后转到工具 -> 选项。在此设置公共符号路径和本地符号路径,请参阅下图。
复选框记录时解析符号表示我们是否要在记录时解析符号。如果我们的应用程序较小且不占用大量 RAM,则可以选中此选项,但对于使用大量内存并在服务器上长时间运行的应用程序,在记录时解析符号不是一个好选择,因为系统在收集堆栈帧和解析每个堆栈帧的符号时会挂起(在大规模应用程序中,可能存在大量堆栈帧)。我建议稍后解析符号,因此不要选中此复选框。您还需要指定要存储生成日志的日志文件路径。单击“确定”,即可完成所需的初始设置。
附加到进程
LeakDiag
的主窗口将如下所示:
在此列表框中,您将看到所有可用的进程,就像我们在任务管理器中看到的那样,还有一个列表询问内存分配器。以下是所有列出分配器的含义:
- 虚拟分配器 (
VirtualAlloc
) - Windows 堆分配器 (
HeapAlloc
)[默认] - COM 分配器 (
CoTask
) - C 运行时分配器 (
msvcrt new
) - TLS 插槽分配器 (
TlsAlloc
)
在上述所有分配器中,重要的是 Windows 堆分配器和 COM 分配器,它们在大多数情况下会导致泄漏。我们也可以通过按住 Ctrl 键同时选择多个分配器。
现在,选择合适的分配器后,单击“开始”以启动代码分析。经过一段时间和间隔后,通过单击“日志”按钮获取堆栈快照,LeakDiag
将根据所选选项(解析符号)花费一些时间进行日志记录。我们可以通过单击“日志”按钮在固定间隔后拍摄快照。这将收集所有已分配内存直到那时仍未释放的堆栈帧。我们应该尽可能多地拍摄快照,快照越多,越容易找到泄漏的堆栈。我们还可以通过修改 autodiag.ini
文件来自动化快照拍摄过程,您可以在 LeakDiag
安装的文件夹中找到此文件。您还可以通过修改以下注册表项来完成此设置:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\LeakDiag\EnableAutoDump
此密钥允许您启用或禁用自动转储功能。
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\LeakDiag\AutoDumpInterval
此密钥允许您选择生成日志的间隔。
好了,现在我们已经定期收集了日志,是时候分析日志了。
分析日志
在我们开始分析日志之前,如果我们尚未解析符号(我在上一节中提到的复选框),那么现在是时候这样做了。打开命令提示符,转到 LeakDiag
的安装文件夹,然后运行 sdecode.exe 命令来查看用法,您将看到以下用法:
sdecode /z <path to .dmp file> [/y <sympath>] [/i <imagepath>] inputfile outputfile
即
sdecode /z c:\memtest.dmp /y c:\winnt;srv*\\symbols\symbols Log123.xml NewLog.xml
此实用程序非常有用,因为我们可以在不影响进程性能的情况下收集未解析的堆栈帧,然后可以解析其符号。请记住,文件名约定不应更改,否则我们将无法使用 LDParser
或 LDGrapher
对其进行分析。
我们可以通过三种方式分析 XML 文件中的日志。
1. 阅读 XML 并手动分析
这是一个稍微棘手且耗时的分析堆栈帧的过程,但它能为我们提供有关进程中泄漏的更清晰、更好的图景。精通阅读 XML 文件将有助于我们更容易地理解 LDParser
和 LDGrapher
工具。
XML 主要包含三个部分:
- XML 模式
LEAKS
标签,其中包含已分配内存但未释放的所有堆栈帧SUMMERY_INFO
标签,此标签包含一些进程和内存信息以及包含在进程中的模块
请参阅第二部分中的堆栈帧。此部分包含多个 STACK
标签,其中提到了堆栈帧。
<STACK numallocs="05" size="015833497" totalsize="079167488">
<STACKSTATS>
<SIZESTAT size="01048576" numallocs="01" type="MEM_RESERVE"/>
<SIZESTAT size="02097152" numallocs="01" type="MEM_RESERVE"/>
<SIZESTAT size="0524288" numallocs="01" type="MEM_RESERVE"/>
<ASSOCIATED_STACKS stackid="23AB8548" type="MEM_COMMIT"
numallocs="02" totalsize="024575"/>
<ASSOCIATED_STACKS stackid="1F9C3EE8" type="MEM_COMMIT"
numallocs="01" totalsize="024576"/>
<ASSOCIATED_STACKS stackid="1F9C4008" type="MEM_COMMIT"
numallocs="01" totalsize="012288"/>
</STACKSTATS>
<FRAME num="0" dll="" function="" offset="0xC0DECAFE"
addr="0xc0decafe" filename="" line=""/>
<STACKID>23AB40E8</STACKID>
</STACK>
堆栈分配的总大小显示在上方的突出显示部分中,以大小和总大小显示。ASSOCIATED_STACKS
显示该区域中的所有关联堆栈,通过一点点智慧,我们可以读取多个文件(每个截图一个文件,即我们上面创建的日志)中的受影响堆栈,由 STACKID
标识,并查看实际泄漏发生的位置。为此,我们需要获取多个文件并逐一跟踪这些文件中的每个堆栈,如果堆栈值的总大小持续增加,甚至长时间保持不变,那么我们可以将该堆栈视为可疑堆栈,并检查该特定堆栈分配的内存是否已正确释放。对所有具有较高总大小值的堆栈重复上述过程,并相应地跟踪泄漏,您可能会发现此过程有点繁琐,但一旦您掌握了它,这将是您能找到的最佳过程。
或者,您也可以编写一个脚本来解析 XML 并创建 XSL 文件;许多经验丰富的开发人员都遵循这种技术。
2. LDParser
这是我们可以用来解析生成的 XML 文件并以表格格式查看数据的工具;我在网上搜索过,但找不到它。
3. LDGrapher
这是 Microsoft 提供的一个可再发行工具,可在 Microsoft FTP 服务器上获得。我们可以在本地安装它,并将生成的 XML 文件作为输入,该工具将为我们提供堆栈的图形表示,如下所示。

在这里,LDGrapher
会选取受影响最大的堆栈,并以不同的颜色显示给我们。我们可以双击任何一行来打开相应的堆栈,并查看该分配的起点。
要在 LDGrapher
中查看堆栈,我们需要选择仅一种类型的分配以及该分配的后续截图文件,否则我们将无法看到任何输出。
我希望关于 LeakDiag
的内容就这么多了,如果您发现任何新信息,请随时添加。
历史
- 2010 年 9 月 10 日:初始发布