我正在阅读Josh Smith 的一篇博客文章,其中他使用缓存机制来“减少托管堆碎片”。他的缓存减少了正在创建的短期对象的数量,代价是执行速度稍慢。
在像 C# 这样的托管语言中,托管堆碎片有多少问题?如果是问题,您如何诊断?在什么情况下您通常需要解决它?
我正在阅读Josh Smith 的一篇博客文章,其中他使用缓存机制来“减少托管堆碎片”。他的缓存减少了正在创建的短期对象的数量,代价是执行速度稍慢。
在像 C# 这样的托管语言中,托管堆碎片有多少问题?如果是问题,您如何诊断?在什么情况下您通常需要解决它?
什么时候
不会太快。拥有短寿命的对象通常非常便宜。为了使缓存能够盈利,必须有(非常)许多候选者,并且他们应该活得足够长以使其能够传给下一代。
如果是问题,您如何诊断?
使用 Profiler。我不太确定这篇文章的作者是否这样做了。
在像 C# 这样的托管语言中,托管堆碎片有多少问题?
据我所知,这种情况很少见。.NET 有一个压缩垃圾收集器,可以防止大多数形式的碎片。大对象堆有时会出现问题。
编辑:
当您浏览文章下方的评论时,您会发现有人对其进行了测量,并发现缓存比每次创建新的 eventargs 慢很多。
结论:在开始优化之前进行测量。这不是一个好主意/例子。
除非您每秒处理 10K+ 小型短期对象,否则在具有合理 RAM 数量的现代计算机上,这根本不是问题。
所以首先你应该在所有合理的场景中运行代码,如果它足够快——别担心。
如果您对速度不满意,有时会看到代码“阻塞”或只是好奇,您可以监控各种 .NET 内存统计信息(http://msdn.microsoft.com/en-us/library/x2tyfybc.aspx ) 在性能监视器应用程序中(作为 Windows 的一部分提供)。具体来说,您对 GC 中的 % Time 感兴趣。
redgate ANTS profiler 也监控这些统计数据。
托管堆碎片通常是由于对象的固定。当托管代码将对象指针传递给本机代码并且由于引用传递给本机代码而无法移动对象时,对象将被固定。当有很多 I/O 活动时,这很常见。如上所述,它通常只发生在 LOH 中。
下面是Gen0 堆中的分片示例
与此处给出的其他答案不同,我声明:是的,应该注意碎片化!它不仅适用于托管堆,而且适用于所有应用程序处理(至少)
由于 LOB 没有被压缩,随着时间的推移,一旦对象的大小和数量超过某个值(这与可用的总最大堆大小有关),它很可能会变得碎片化。如果是这样,唯一安全的方法是限制对这些对象的即时持有引用的数量。如果可以重用池化的对象,缓存(池)只会有所帮助。有时,如果这些资源由不同长度 fe 的数组组成,它们可能不容易重用。因此,池化在这里可能没有多大帮助。
如何检测它?当 LOB 堆上的压力很大时。如何找出它是?同时使用 .NET 性能计数器“Collection Count Gen 0...2”。如果从 LOB 中分配了太多的大对象,所有的计数器都会以相同的方式演化。意思是,基本上所有的收藏都是昂贵的第 2 代收藏。在这种情况下,应该做点什么。
对于较小的对象,我会让 GC 在 Gen 0 集合中完成所有工作,不用担心。