.net集合内存优化 - 这种方法会起作用吗?

时间:2011-01-29 11:26:56

标签: c# .net performance collections

就像几乎所有其他大型.NET应用一样,我当前的C#项目包含许多.net个集合。
有时我从一开始就不知道Collection(List / ObservableCollection / Dictionary / etc。)的大小是多少。
但是很多时候我确实知道它会是什么。

我经常得到一个OutOfMemoryException我被告知它不仅可能因为流程大小限制而且还因为碎片而发生。

所以我的问题是这个 - 每当我知道它的预期大小帮我防止至少一些碎片问题时,会设置集合的大小(使用构造函数中的capacity参数)吗?

此引用来自msdn

  

如果集合的大小可以   估计,指定初始   容量消除了需要   执行一些调整大小   添加元素时的操作   清单。

但是,我仍然不想开始更改我的代码的大部分内容,因为这可能不是真正的问题。

有没有帮助你们解决内存不足的问题?

5 个答案:

答案 0 :(得分:4)

如果摆脱OutOfMemory问题,指定初始大小很少 - 除非你的集合大小是数百万个对象,在这种情况下你真的不应该保留这样的集合。

调整集合大小涉及使用新的附加大小定义一个全新的数组,然后复制内存。如果您已经接近内存不足,是的,这可能会导致内存不足,因为无法分配新阵列。

但是,在100个中有99个,您的应用中存在内存泄漏,而收集调整问题只是其中的一个症状。

答案 1 :(得分:3)

如果您正在使用OOM,那么您可能对数据过于激进,但要回答这个问题:

是的,这可能有助于某些 - 好像它必须通过加倍来增加集合,它最终可能会为底层数组分配和复制两倍的内存 (或者更准确地说,对于先前丢弃的较小副本)。大多数这些中间数组都会被迅速收集,但是当它们变大时,你会使用“大对象堆”,这很难压缩。

从正确的大小开始会阻止数组的所有中间副本。

但是,它还取决于数组中 的重要性。通常,对于类,每个对象中有更多数据 (加上引用的开销等) - 这意味着列表不一定是内存使用的最大罪魁祸首;你可能会烧掉对象上的大部分内存。

请注意,x64将允许更多整体空间,但数组限制为2GB - 如果每个引用的大小增加一倍,则会将数组的最大有效长度减半。

就个人而言,我会考虑将大型集合分解为较小的列表;例如,参差不齐的列表。

答案 2 :(得分:2)

.NET有一个竞争垃圾收集器,因此您可能不会在正常的.NET堆上遇到碎片问题。但是,如果您使用大量非托管内存(例如通过GDI +,COM等),则可能会出现内存碎片。此外,大型对象堆不会被压缩,因此也可能会碎片化。 IIRC如果物体大于80kb,则将物体放入LOH。因此,如果您有许多包含超过20k对象的集合,则可能会出现碎片问题。

但是,不要猜测问题可能在哪里,最好将问题缩小到更多:何时获得OutOfMemoryExceptions?当时应用程序使用了多少内存?使用像WinDbg或内存分析器这样的工具,您应该能够找出LOH中有多少内存。

也就是说,如果你知道的话,提前设置List和其他数据结构的容量总是一个好主意。否则,每次添加项目并达到容量限制时,列表将使其容量加倍,这意味着许多不必要的分配和复制操作。

答案 3 :(得分:1)

为了解决这个问题,您必须了解基础知识并查明代码中的问题。

如果你有合理的估计,设置初始容量总是一个好主意。如果您只有近似猜测,请分配更多。

碎片只能在LOH(超过80 kB的对象)上发生。要防止它,请尝试分配相同大小的块。矛盾的是,解决方案可能是有时分配更多内存而不是实际需要的内存。

答案 4 :(得分:0)

答案是,是预先定义集合的大小将提高性能和内存优化并减少碎片。请在此处查看我的答案,了解原因 - If I set the initial size of a .NET collection and then add some items OVER this initial size, how does the collection determine the next resize?

但是,如果不分析应用程序上的内存转储或内存分析,就不可能确切地说出OOM的原因是什么。因此,如果此优化将解决问题,则无法猜测。