【问题标题】:Find memory leaks with WinDbg when lots of objects are present in Gen2当 Gen2 中存在大量对象时,使用 WinDbg 查找内存泄漏
【发布时间】:2012-02-07 04:23:45
【问题描述】:

我的 .NET 应用程序存在内存问题,在初始化和加载所有内容后,我的应用程序开始在 Gen2 堆中消耗大约 1GB。随着时间的推移(4-5 小时),它会慢慢消耗 Gen2 堆中的 4GB。我使用 WinDbg 来分析我看到的一些对象类型(以及相关的内存使用)正在增加的事情。

所有在实例中增长的对象(和内存使用)都被相同的父对象类型引用。这个父对象类型有大约 3900 个实例——这永远不会改变。不知何故,我将子对象添加到这些父实例中的一些,但我没有一个好方法来查看正在添加的 3900 个实例中的哪一个。

!DumpHeap -mt 会显示我所有的父类型,但大小都是一样的,因为它不包括子类型。

!ObjSize 也会计算子元素的大小,但一次只会使用一个对象作为参数(或所有类型的所有对象 - 不仅仅是我的父类型 - 这是太多的对象)

查看子对象并将它们追溯到父对象也无济于事,因为这些类型有几百万种,我看不到进行某种聚合跟踪的方法。

CLRProfiler 和 ANTS 之类的工具会大大降低我的应用程序的速度(ANTS 更少),以致问题在任何合理的时间内发生。

我已尝试使用通常运行的一小部分数据来运行我的应用程序,以便更轻松地进行调试,但我在这里没有遇到内存问题。我认为我的整个数据集中有一些边缘情况会导致奇怪的事情,但我不知道这些边缘情况是什么,以便将它们隔离到我的整个数据集的一个子集中。

已对此进行了广泛阅读,但没有看到任何人建议在 Gen2 中应该存在的大量对象以及不断增加的少量相同类型的对象时该怎么做。

任何提示将不胜感激。

【问题讨论】:

    标签: c# .net debugging memory-leaks windbg


    【解决方案1】:

    您可以在父类型的所有对象上使用!objsize

    .foreach (address {!dumpheap -short -type MyParentType}) {!objsize ${address}}
    

    如果你的类名不够唯一,也可以通过方法表

     !name2ee MyModule MyParentType ; *** to get the method table
     .foreach (address {!dumpheap -short -mt <methodtable>}) {!objsize ${address}}
    

    【讨论】:

      【解决方案2】:

      我假设您为此使用了 SOS。更好的选择是使用PSSCOR2PSSCOR4(取决于您使用的运行时版本)。 !dumpheap 的 PSSCOR 版本有一个额外的 delta 列,它可以帮助您检测哪些实例随着时间的推移而增长。

      【讨论】:

      • 谢谢布赖恩。我正在使用 SOS,并且我最近检查了 PSSCOR4(尽管大多数新选项都是针对 ASP.NET),希望它会有所帮助。 !DumpHeap 确实有更改列,但父对象没有根据 !DumpHeap 增长,因为 !DumpHeap 不计算大小中的子对象。
      • @Dave:虽然 PSSCOR 确实有很多特定于 ASP 的命令,但即使对于 IMO 的 SOS 命令的更新版本也是值得的。无论如何,我假设孩子们也是堆分配的,所以你应该能够检测到那里的增加。
      • 确实 PSSCOR 的添加很有用,只是不确定它们在这种情况下是否有帮助。孩子是堆分配的,但是 !DumpHeap 不计算父母报告的大小中的孩子,只有 !ObjSize 。我也不能简单地抛弃孩子并查看他们的大小,因为孩子的大小没有增长,子实例正在增长。转储 200 万个实例,然后追溯每个实例,找出哪个父级在他们持有的实例数量上真正增长,至少很难说!不确定我是否遗漏了您的建议。告诉我。
      • @DaveRobinson:我不确定我是否遵循这些类型的使用方式的确切性质。如果您不确定子项是在哪里创建的,您可以在相关构造函数上设置断点并自动转储调用堆栈。您可能应该只将输出记录到文件中,以便之后进行搜索。
      • 您知道是否会有适用于 .NET 4.5/4.6 的 PSSCOR 版本吗? PSSCOR4 仅适用于 .NET 4.0。如果微软不再有兴趣维护它,它是否可以开源?
      【解决方案3】:

      有趣的谜题。如您所知,当对象在集合中幸存下来时,它们会被提升为 gen2,因为它们被长期存在的东西引用。您没有说这是什么类型的应用程序 - asp.net、WPF、winforms 等,所以我们必须做出一些猜测。

      您可以尝试的一种策略是记录。您说有 3900 个“父对象”实例正在添加某些东西 - 您可以在接受新对象的父对象上检测方法吗?也许通过记录这些添加内容,您可以了解它们的来源。

      【讨论】:

      • 感谢@n8wrl 的反馈。这是一个 Windows 服务,尽管它也可以编译为我从命令行运行的直接控制台应用程序。我开始调试添加父对象的地方,但是 VS2010 使用隐式“远程调试”来调试 64 位应用程序,因为 VS 只有 32 位。远程调试器在我的内存问题发生之前一直崩溃(谷歌告诉我的一个常见问题)。我现在正在向控制台写入消息。正在考虑 WinDb 一定有更好的方法,甚至可能不是 SOS。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-29
      • 2018-10-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多