4

很长一段时间以来,我一直在尝试修复应用程序中的内存泄漏。几个月前,我注意到在我的应用程序中,超过 95% 的对象被提升到 Gen2;我有一些非常基本的问题,我无法在书中找到。我希望你们能帮助我:

  1. 拥有这么多 Gen2 对象是个坏消息吗?在我拍摄的每个快照中,我都会在 WinDbg 中获得大约 77,000 个 Gen2 对象、100 个 Gen1 对象和 10 个 Gen0 对象。
  2. 我怎样才能找出这么多对象被提升的原因?有什么好的工具吗?我一直在使用 WinDbg/SOS,但运气不佳

先感谢您。

4

1 回答 1

14

拥有这么多 Gen2 对象是个坏消息吗?

这不是坏消息。这可能意味着 GC.Collect 刚刚运行,或者它经常运行,并且您有足够的可用内存 - 因此 Gen2 中的对象不会被收集。这是另一个 StackOverflow 问题的一些很好的解释, 即使需要垃圾收集也不会发生

开始垃圾收集时,GC 确定需要收集哪些代(0、0+1 或全部)。每一代都有一个由 GC 确定的大小(它可以随着应用程序的运行而改变)。如果只有第 0 代会超出其预算,那是唯一将收集垃圾的代。如果第 0 代幸存的对象会导致第 1 代超出其预算,那么第 1 代也将被收集并将其幸存对象提升到第 2 代(这是微软实现中的最高代)。如果也超出了第 2 代的预算,则会收集垃圾,但对象无法提升到更高的一代,因为不存在。

所以,这里有重要的信息,在最常见的 GC 启动方式中,只有在第 0 代和第 1 代都已满时才会收集第 2 代。此外,您需要知道超过 85,000 字节的对象不会存储在具有 0、1 和 2 代的普通 GC 堆中。它实际上存储在所谓的大对象堆 (LOH) 中。LOH 中的内存仅在 FULL 收集期间(即第 2 代收集时)被释放;永远不会只收集第 0 代或第 1 代。

对于你的第二个问题:

我怎样才能找出这么多对象被提升的原因?有什么好的工具吗?我一直在使用 WinDbg/SOS,但运气不佳

Windbg 和 SOS 很好 :) 在这种情况下,我建议添加 psscor2(或 psscor4,如果使用 .NET 4.0)您需要使用 psscor 轻松转储特定生成的对象。

这是下载psscor2psscor4 dll 的官方链接。将它们的适当版本放在安装 Windbg 的文件夹中。x86 版本的 dll 到 x86 文件夹(C:\Program Files (x86)\Debugging Tools for Windows),x64 版本的 dll 到 x64 文件夹(C:\Program Files\Debugging Tools for Windows (x64))。

然后您将能够运行下一个命令:

    !dumpheap -gen 2

当 psscor 有时,SOS 没有简单的命令来仅转储特定代的对象。

使用此命令,您可以创建类似的结构

.foreach (obj { !dumpheap -gen 2 -short }) { !do ${obj} }

或者

.foreach (obj { !dumpheap -gen 2 -type ExactTypeName -short }) { !gcroot ${obj} }

找出第 2 代中对象的主要类型,以及哪些方法引用了它们。

正如您所说,您的主要想法是查找内存泄漏,您应该使用更通用的方法,并且不仅要分析生成。以下是我关于分析高内存使用问题的帖子:

托管内存

http://kate-butenko.blogspot.com/2012/06/investigating-memory-issues-high-memory.html

非托管内存

http://kate-butenko.blogspot.com/2012/07/investigating-issues-with-unmanaged.html

http://www.codeproject.com/Articles/31382/Memory-Leak-Detection-Using-Windbg

如果您仍然停留在某个步骤上,请留下您的问题。

于 2012-08-10T14:09:44.987 回答