17370845950

Windows程序内存泄漏(Memory Leak)分析之UMDH

小木通过任务管理器观察到线上程序的内存持续增长,怀疑是内存泄漏的问题。用户态内存泄漏可能包括

句柄泄漏
堆内存泄漏
socket
gdi对象
等。对于
c++
程序员来说,最常见的无疑是
堆内存泄漏
,即通过
malloc
new
从堆上申请的内存使用完后未被释放,导致程序使用的内存不断增加。

为了分析这个问题,小木使用了

UMDH
,这是
Windbg
工具集中的一个强大工具,用于记录程序在不同时间点的堆内存申请信息,并通过比较两次记录来查找内存泄漏。小木首先编写了一个测试程序来熟悉工具的使用。该程序每隔十秒钟调用一次
MemorLeakFunction
,在函数中从堆上申请一段内存空间但未释放。

#include 
#include 
#include 

void MemoryLeakFunction() { const int STR_SIZE = 100; char * pStr = new char [STR_SIZE]; strcpy_s(pStr, STR_SIZE, "Memory Leak Sample"); std::cout << "Memory allocated: " << pStr << std::endl; }

int main() { while (true) { MemoryLeakFunction(); std::this_thread::sleep_for(std::chrono::seconds(10)); } return 0; }

小木使用以下步骤来分析内存泄漏:

  1. 使用

    gflag
    工具:通过命令
    "C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\gflags" -i MemoryLeak.exe +ust
    来配置
    MemoryLeak.exe
    程序,使其在申请堆内存时记录函数调用栈。图形化界面中开启
    Create user mode stack trace database
    选项。

  2. 运行测试程序

    MemoryLeak.exe

  3. 配置Symbol文件:将程序的symbol文件

    MemoryLeak.pdb
    拷贝到
    mysymbols
    目录下,并运行命令
    Set _NT_SYMBOL_PATH=C:\mysymbols;SRVC:\symbolshttps://www./link/f3a45758fe1e808fd1d41b62d7784a93
    来配置Symbol路径。

  4. 保存初始内存记录:运行命令

    "C:\Program Files (x86)\Windows Kits\Debuggers\x64\umdh" -pn:MemoryLeak.exe -f:C:\umdhlog\begin.log
    来保存程序当前的堆内存申请记录到
    C:\umdhlog\begin.log

  5. 等待一段时间后再次保存内存记录:假设等待5分钟后,运行命令

    "C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\umdh" -pn:MemoryLeak.exe -f:C:\umdhlog\end.log
    来保存新的堆内存申请记录到
    C:\umdhlog\end.log

  6. 比较两次内存记录:运行命令

    "C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\umdh" C:\umdhlog\begin.log C:\umdhlog\end.log -f:c:\umdhlog\diff.log
    来比较两次记录,找出增加的堆内存请求及其调用栈,并将结果导出到
    c:\umdhlog\diff.log

diff.log
中,可以看到增加的内存申请的函数调用栈,例如:

+    1194 (  157c -   3e8)     37 allocs  BackTrace1