调查内存泄漏 - 提交的内存增长 - 堆很好

Investigating memory leak - Commited memory grows - Heap is fine

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

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

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

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

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

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

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

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

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

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

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

Because of the fact that the heap is fine and the private bytes are directly allocated with VirtualAlloc() I can exclude 'our' managed application code from the list of possible leak candidates.

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

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

如果你只有转储,你可以用 .loadby sos clr 加载 并使用 !dumpheap -stat 查看你的内存在哪里。输出将列出每个 class.

的对象数量和总大小

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

故障转储仅显示特定时间点的内存。使用专门的内存泄漏工具分析此问题的各种方法的好处是,它们将跟踪分配的堆栈跟踪,并更好地了解随时间发生的情况。

感谢 Alex K. 推荐 DebugDiag,如您在屏幕截图中所见,它提供了巨大的帮助:

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