调查记忆泄漏

时间:2012-04-05 14:16:31

标签: windows debugging memory-management memory-leaks windbg

我们的应用程序中存在缓慢的内存泄漏,我已经尝试分析泄漏原因,已经完成以下步骤:

  1. 在GFlags中启用用户模式堆栈跟踪数据库
  2. 在Windbg中,键入以下命令:!heap -stat -h 1250000 (其中1250000是具有泄漏的堆的地址) 在比较多个转储后,我发现大小 0xC 的内存块会随着时间的推移而增加,并且可能是泄漏的内存。
  3. 输入以下命令:!heap -flt s c 给UserPtr这些分配,最后:
  4. 在其中一些地址上键入!heap -p -a address 始终会显示以下分配调用堆栈:
  5. 0:000> !heap -p -a 10576ef8

    address 10576ef8 found in
    _HEAP @ 1250000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        10576ed0 000a 0000  [03]   10576ef8    0000c - (busy)
        mscoreei!CLRRuntimeInfoImpl::`vftable'
        7c94b244 ntdll!RtlAllocateHeapSlowly+0x00000044
        7c919c0c ntdll!RtlAllocateHeap+0x00000e64
        603b14a4 mscoreei!UtilExecutionEngine::ClrHeapAlloc+0x00000014
        603b14cb mscoreei!ClrHeapAlloc+0x00000023
        603b14f7 mscoreei!ClrAllocInProcessHeapBootstrap+0x0000002e
        603b1614 mscoreei!operator new[]+0x0000002b
        603d402b +0x0000005f
        603d5142 mscoreei!GetThunkUseState+0x00000025
        603d6fe8 mscoreei!_CorDllMain+0x00000056
        79015012 mscoree!ShellShim__CorDllMain+0x000000ad
        7c90118a ntdll!LdrpCallInitRoutine+0x00000014
        7c919a6d ntdll!LdrpInitializeThread+0x000000c0
        7c9198e6 ntdll!_LdrpInitialize+0x00000219
        7c90e457 ntdll!KiUserApcDispatcher+0x00000007
    

    这看起来像线程初始化调用堆栈,但我需要了解更多。 为了确定泄漏的确切原因,您建议采取的下一步措施是什么。

2 个答案:

答案 0 :(得分:6)

使用GFlags时记录的堆栈是在不使用.pdb的情况下完成的,通常不正确。 由于您已将泄漏跟踪到给定堆上的特定大小,因此您可以尝试 在RtlAllocateHeap中设置实时中断并使用适当的符号检查windbg中的堆栈。我使用了以下内容并取得了一些成功。您必须编辑它以适合您的堆和大小。

 $$ Display stack if heap handle eq 0x00310000 and size is  0x1303
 $$ ====================================================================
bp ntdll!RtlAllocateHeap "j ((poi(@esp+4) = 0x00310000) & (poi(@esp+c) = 0x1303) )'k';'gc'" 

也许你会为罪犯获得另一个筹码和其他想法。

答案 1 :(得分:2)

首先,新运算符是new []运算符,因此是否有相应的delete[]调用,而不是普通的delete调用?

如果您怀疑这段代码,我会在其周围放置测试工具,例如将其置于循环中并执行100或1000次,它是否仍然会按比例泄漏。

您还可以使用进程资源管理器或使用GetProcessInformation以编程方式测量内存增量。

另一个显而易见的事情是看看当你注释掉这个函数调用时会发生什么,内存泄漏会消失吗?如果可能的话,您可能需要对代码执行二进制切换,以便通过注释掉代码将每次可能的可疑代码减少一半(大致),但是,更改代码的行为可能会导致更多问题或相关的代码路径问题导致内存泄漏或奇怪的行为。

修改 当您在托管环境中工作时,请忽略以下内容。

您还可以考虑使用STL或更好的boost引用计数指针(如shared_ptrscoped_array来表示数组结构来管理对象的生命周期。