拥有这么多 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 轻松转储特定生成的对象。
这是下载psscor2和psscor4 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
如果您仍然停留在某个步骤上,请留下您的问题。