【问题标题】:Investigating memory leak - Commited memory grows - Heap is fine调查内存泄漏 - 提交的内存增长 - 堆很好
【发布时间】:2016-08-03 12:10:24
【问题描述】:

我正在调查我们的 C#/WPF/.NET 4.51 应用程序中可能存在的内存泄漏。

我在启动后直接拍摄了应用程序的快照,并在分配的内存超过顶部的几个小时后拍摄了快照。

我使用 VisualStudio 的进程转储工具检查了托管堆实例。一切看起来都很好。

在 WinDbg 中打开转储似乎证实了这一点,因为堆和堆栈以我预期的方式增长(+50MB)(左:第一次转储,右:最后一次转储):

让我恼火的是,提交页面的大小增长了很多(左:第一次转储,右:最后一次转储):

此外,VMMap 将这个巨大的提交块显示为“私有数据”(与上面的转储无关。屏幕截图是大约一个小时后拍摄的):

请纠正我:
由于堆很好,并且私有字节直接使用 VirtualAlloc() 分配,我可以从可能的泄漏候选列表中排除“我们的”托管应用程序代码。

有没有办法缩小泄漏的原因?

【问题讨论】:

  • 您是否在使用任何非托管库? debugdiag 2 是一个很好的起点
  • 如果你使用excel插值之类的东西,如果你不释放所有大量的excel部分,垃圾收集器可能需要很长时间才能释放东西。
  • 是的,我们使用了很多外部组件。在停用每个组件之前,我试图将泄漏缩小一点。谢谢。现在正在尝试 DebugDiag...
  • 哪个 windows 版本?在 Windows 10 1607 中,使用带有 WPT/WPR 的 ReferenceSet 跟踪:aloiskraus.wordpress.com/2016/06/26/… 并查看 VALloc 调用堆栈以查看内存分配的位置。
  • 也许 WPA 可以帮助您缩小范围。我会试试xperf - Collect Heap_Launch.cmd。

标签: c# memory memory-leaks windbg


【解决方案1】:

由于堆很好,并且私有字节直接使用 VirtualAlloc() 分配,我可以从可能的泄漏候选列表中排除“我们的”托管应用程序代码。

您会看到 <unknown> 增加了 1.5 GB,这是通过 VirtualAlloc() 分配的内存。这可以是 MSXML、函数的任何直接(“本机”)调用或具有自己的堆管理器的 .NET 的内存(因此不属于 Heap 类别,即 C++ 堆)。

由于您有一个 .NET 应用程序,因此可能是 .NET 代码造成了这 1.5 GB 的内存丢失。

如果你只有转储,你可以用.loadby sos clr 加载 并使用!dumpheap -stat 来查看你的内存在哪里。输出将列出每个类的对象数量和总大小。

从 .NET 的角度来看,内存可能已经被释放,因此它被列为 Free。您可能还想确保垃圾回收已经发生,否则可能会出现误报。

故障转储仅显示特定时间点的内存。使用专门的内存泄漏工具进行分析的各种方法的好处是,它们将跟踪分配的堆栈跟踪,并更好地了解随着时间的推移会发生什么。

【讨论】:

  • 所以MSXML直接调用VirtualAlloc()?
  • @MarcSherman:至少上次我遇到了问题。一定是 2009 年左右,可能是 MSXML 6。
【解决方案2】:

我们曾经在工作中遇到过类似的问题,我们使用名为 dotMemory 的 JetBrains Memory Profiler 解决了它,它可以准确地显示内存泄漏的位置。

我相信他们有 30 天的试用期。

https://www.jetbrains.com/dotmemory/features/

【讨论】:

  • @thomai:你确定吗?您是否阅读了我的回答并取得了任何进展?
【解决方案3】:

感谢 Alex K. 推荐 DebugDiag,正如您在屏幕截图中看到的那样,它提供了巨大的帮助:

我们使用 WPF 的 WebBrowser(使用 ActiveX 控件实现)来显示一个运行大量 java 脚本代码的网页。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-03-11
    • 2016-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-19
    相关资源
    最近更新 更多