假设我们必须创建许多字节数组类型的小对象。大小不一,但总是低于1024字节,比如780,256,953 ......
如果我们总是只分配字节[1024],并且只使用所需的空间,它会不会改善运营商的新效率或GC效率?
UPD:这是为了解析二进制协议消息而创建的短生命对象。
UPD:在两种情况下,对象的数量都是相同的,它只是改变的分配大小(随机与总是1024)。
在C ++中,由于碎片和C ++的新性能,它很重要。但在C#....
答案 0 :(得分:9)
如果我们总是只分配字节[1024],并且只使用所需的空间,它会不会改善运营商的新效率或GC效率?
也许。您将不得不对其进行分析并查看。
我们在Roslyn编译器中分配语法树节点的方式非常有趣,我最终会做一篇关于它的博客文章。在那之前,你问题的相关部分是这个有趣的琐事。我们的分配模式通常涉及分配“底层”不可变节点(我们称之为“绿色”节点)和包含它的“外观”可变节点(我们称之为“红色”节点)。正如您可能想象的那样,我们最终会成对分配这些:绿色,红色,绿色,红色,绿色,红色。
绿色节点是持久的,因此是长寿的;外墙是短暂的,因为它们在每次编辑时都被丢弃。因此,垃圾收集器经常出现绿色/孔洞/绿色/孔洞/绿色/孔洞,然后绿色节点向上移动一代。
我们的假设一直是使数据结构更小将始终提高GC性能。较小的结构等于分配的内存较少,等于较少的收集压力,等于较少的收集,等于更多的性能,对吧?但是我们通过分析发现,在这种情况下使红色节点更小实际上降低了 GC性能。 关于孔的特定尺寸的某些东西以某种奇怪的方式影响GC ;不是垃圾收集器内部的专家,对我来说这是不透明的。
那么更改分配的大小是否有可能以某种不可预测的方式影响GC? 是的,这是可能的。但是,首先,它是不太可能,其次是无法知道你是否处于这种情况,直到你真正尝试它在实际场景中并仔细测量GC性能。
当然,您可能没有关于GC性能的门控。 Roslyn进行了如此多的小型分配,因此我们调整GC影响行为至关重要,但我们会做一些疯狂的小分配。绝大多数.NET程序都没有像我们那样强调GC。如果你是少数几个以有趣的方式强调GC的程序,那么就没有办法了解它;您将需要分析和收集经验数据,就像我们在Roslyn团队中所做的那样。
如果你不是那么少数人,那么不要担心GC表现;你可能在其他地方有一个更大的问题,你应该首先处理。
答案 1 :(得分:3)
new
速度很快,导致问题的是GC。所以,这取决于阵列的存在时间。
如果他们只活了很短的时间,我认为分配1024字节数组不会有任何改进。事实上,由于空间浪费,这将给GC带来更多压力,并可能降低性能。
如果它们存在于应用程序的生命周期中,我会考虑分配一个大型数组并为每个小数组使用它。您需要对此进行分析以确定它是否有帮助。
答案 2 :(得分:1)
实际上,分配或清除字节数组只需要一条指令,无论其大小如何。 (我说的是你的情况。有例外)
你不应该担心垃圾收集的性能方面,除非你确定它是你的应用程序的瓶颈(即你创建了大量具有复杂关系的引用,并在之后不久抛出它...而垃圾收集很明显。)
要阅读有关.NET GC性能问题的众所周知(且非常有用)的网站的优秀故事(在一个令人印象深刻的用例中),请参阅此博客。 http://samsaffron.com/archive/2011/10/28/in-managed-code-we-trust-our-recent-battles-with-the-net-garbage-collector;)
但关于GC的最重要的事情是:在确定您遇到问题之前,永远不要进行优化。因为如果你这样做,你可能会有一个。应用程序很复杂,GC在运行时与其的每个部分进行交互。除了简单的案例,预先预测其行为和瓶颈似乎(在我看来)很难。
答案 3 :(得分:0)
我也不认为只分配1024字节数组会改善GC。 由于GC 不确定,我也认为这不是你的问题。
您可以使用阵列周围的using {}
语句来更快地释放内存(可能),从而影响GC。
答案 4 :(得分:0)
我不认为GC会成为问题和/或瓶颈。
分配不同大小的对象并以不同的顺序释放它们可能会导致碎片堆内存。所以这就是分配相同大小的对象可能派上用场的地方。
如果您确实分配/释放了很多并且确实将此视为您的瓶颈,请尝试使用本地对象缓存重新使用这些对象。这可能会导致性能提升,特别是如果它们是不实现大量逻辑的仅数据对象。如果对象确实实现了很多逻辑并且需要复杂的初始化(RAII模式),我会放弃程序稳健性的性能提升......
HTH
马里奥