我正在调查我们的应用程序中的GC和内存使用,并注意到我们似乎有成千上万的终结幸存者。不幸的是,这个数字并不能真正告诉我我们是否有问题。然而,我们看到了一般性能问题,并且我们确实使用了大量内存,并在GC中花费了大量时间。
理想情况下,我们无法控制的任何内容都应该进入终结队列。这是一个错误,如果它。我可以使用一些方法或工具来检查这个吗?我听到的一个建议是使用终结器进行特殊构建,只要它们被执行就会记录,但这需要付出很多努力,并且只适用于我们拥有类型的对象。有更简单的方法吗?
是否值得调查最终幸存者?如果是这样,怎么样?
答案 0 :(得分:5)
将WinDbg与Psscor2或Psscor4扩展名一起使用(取决于您的应用程序使用的版本)。不幸的是,.NET 4.5还没有版本。设置调试环境(安装WinDbg并复制到其文件夹Psscor文件)后,创建进程的转储。例如,借助Procdump工具
,您可以轻松完成procdump -ma <PID>
然后使用File加载转储 - &gt;打开Crush Dump选项。加载适当版本的Psscor:
.load psscor4
然后执行命令从Microsoft服务器下载符号(如果需要),确保您有互联网连接:
!symfix
从现在起你应该可以访问很多非常有趣的命令(查找!help
列出它们)。要查看终结队列:
!finalizequeue
在那里你将有一个对象列表,如:
7aa143e0 166 20,584 System.Diagnostics.PerformanceCounter
79b5f6c8 543 21,720 System.Reflection.Emit.DynamicResolver
673893a8 953 22,872 System.Web.HttpResponseUnmanagedBufferElement
这可能对你有很大帮助。但您也可以检查这些对象(!do 7aa143e0
),查找引用(!gcroot <address>
)等。
答案 1 :(得分:0)
是否值得调查最终幸存者?
是的,因为最终确定会对性能和资源产生影响。
若然,怎么样?
我建议进行代码检查。
您的类型是否有终结器?如果是,这些是否正确实施?如果直接控制非托管资源,则只需要终结器。如果你有一个终结器,你应该实现IDisposable
并使用确定性清理。这样做可以确保永远不会调用终结器。 GC.SuppressFinalize(this)
方法中对Dispose
的调用可确保实例未完成,因为它已被处理掉。
如果终结器在库代码中,那么这些类型将(或应该)实现IDisposable
,您必须确定性地处理这些实例以确保永远不会调用它们的终结器。