调查内存泄漏 - 已分配的内存增长 - 堆是正常的。

3
我正在调查我们的C#/WPF/.NET 4.51应用程序可能存在的内存泄漏问题。
我在启动应用程序后立即拍摄了快照,并在分配的内存超过顶部后几个小时再次拍摄了快照。
我使用VisualStudio的进程转储工具检查了托管堆实例。一切看起来完全正常。
在WinDbg中打开转储似乎证实了这一点,因为堆和栈是按我预期的方式增长的(+50MB) (左: 第一个转储,右: 最后一个转储): WinDbg Heap/Stack 让我感到困惑的是已提交页面的大小大量增加(左: 第一个转储,右: 最后一个转储): WinDbg State summary
此外,VMMap显示了这个巨大的已提交块作为“私有数据”(与上面的转储无关。该屏幕截图是大约一个小时后拍摄的): VMMap image 请纠正我: 由于堆没问题,并且私有字节是直接使用VirtualAlloc()分配的,因此我可以将“我们”的托管应用程序代码从可能泄漏的候选列表中排除。
有没有办法缩小泄漏原因的范围?

你是否使用了任何非托管库?debugdiag 2 是一个很好的起点。 - Alex K.
如果您使用诸如 Excel 插值之类的内容,如果您不释放所有 Excel 部件的多样性,垃圾回收器可能需要很长时间才能释放这些内容。 - BugFinder
是的,我们正在使用相当多的外部组件。在停用每个组件之前,我正在尝试缩小泄漏范围。谢谢。我现在正在尝试 DebugDiag... - Tho Mai
1
哪个Windows版本?在Windows 10 1607中,使用WPT/WPR进行ReferenceSet跟踪:https://aloiskraus.wordpress.com/2016/06/26/new-beta-of-windows-performance-toolkit/并查看VAlloc调用堆栈以查看内存分配的位置。 - magicandre1981
也许 WPA 可以帮助您缩小范围。我建议尝试使用 xperf - Collect Heap_Launch.cmd - Lieven Keersmaekers
3个回答

2
由于堆是 fine(即未垃圾回收的堆),私有字节是直接使用 VirtualAlloc() 分配的,因此我可以将“我们”的托管应用程序代码从可能的泄漏候选列表中排除掉。
您会看到 <unknown> 的内存增加了 1.5 GB,这是通过 VirtualAlloc() 分配的内存。这可能是 MSXML 的内存,任何直接调用该函数的本机调用,或者是 .NET 具有自己的堆管理器(因此不属于 C++ 堆类别)的内存。
由于您有一个 .NET 应用程序,因此很可能是 .NET 代码导致了那 1.5 GB 的内存丢失。
如果您只有转储文件,则可以使用 .loadby sos clr 加载 ,并使用 !dumpheap -stat 查看您的内存在哪里。输出将按类列出对象数量和总大小。

从.NET的角度来看,内存可能已经被释放了,所以它被列为Free。您还需要确保进行了垃圾回收,否则可能会有误报。

崩溃转储只显示某个时间点上的内存情况。使用专门的内存泄漏工具分析这些数据的各种方法有益处,它们将跟踪分配的堆栈跟踪,并更好地了解随时间发生的情况。


MSXML直接调用VirtualAlloc()吗? - Marc Sherman
@MarcSherman:至少我上次遇到问题是在2009年左右,可能是MSXML 6的问题。 - Thomas Weller

1

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

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

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


@thomai:你确定吗?你读了我的回答并且有进展了吗? - Thomas Weller

0

感谢Alex K. 推荐的DebugDiag,正如您在截图中所看到的,它帮了我很大的忙:

DebugDiag-output

我们使用WPF的WebBrowser(通过使用ActiveX控件实现)来显示运行大量JavaScript代码的网页。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接