如果列表的大小合理已知,是否值得初始化列表的集合大小?<T>

问题描述 投票:0回答:3
如果合理已知的话,是否值得初始化

List<T>

 的集合大小?

编辑:进一步讨论这个问题,在阅读第一个答案后,这个问题实际上可以归结为什么是默认容量以及如何执行增长操作,它是否使容量加倍等?

c# generics list
3个回答
85
投票
是的,当您的

List<T>

 变大时,它就变得很重要。确切的数字取决于元素类型和机器架构,让我们选择 32 位机器上的引用类型列表。每个元素将在内部数组中占用 4 个字节。该列表将以容量 0 和空数组开始。第一个 
Add()
 调用将容量增加到 4,将内部数组重新分配为 16 字节。四次 
Add()
 调用后,数组已满,需要再次重新分配。它的大小增加了一倍,容量增加到 8,数组大小增加到 32 字节。之前的数组是垃圾。

根据需要重复此过程,内部数组的多个副本将变成垃圾。

当数组增长到 65,536 字节(16,384 个元素)时,会发生一些特殊的情况。接下来的

Add()

 再次将大小加倍至 131,072 字节。这是超出“大对象”阈值(85,000 字节)的内存分配。现在不再在第 0 代堆上进行分配,而是从
大对象堆中获取。

LOH 上的对象经过特殊处理。它们仅在第 2 代收集期间被垃圾收集。而且堆没有被压缩,移动这么大的块需要太多时间。

根据需要重复此过程,一些 LOH 对象将变成垃圾。它们可能会占用内存相当长一段时间,第 2 代收集不会经常发生。另一个问题是这些大块往往会导致虚拟内存地址空间碎片化。

这不会无休止地重复,

List

类迟早需要重新分配数组,并且它已经变得如此之大,以至于虚拟内存地址空间中没有留下一个空洞来容纳该数组。你的程序将会因为
OutOfMemoryException
而爆炸。通常在所有可用虚拟内存被消耗之前。

长话短说,通过在开始填充

Capacity

之前提前设置
List
,您可以预先保留那个大型内部数组。您不会在大型对象堆中获得所有那些尴尬的释放块并避免碎片。实际上,您将能够在列表中存储更多的对象,并且您的程序运行得更精简,因为垃圾很少。仅当您很清楚列表有多大时才执行此操作,使用您永远无法填充的大
Capacity
是浪费。


19
投票
是的,

根据文档

如果集合的大小可以 估计,指定初始 容量消除了需要 执行多次调整大小 添加元素时的操作 列表(T)。


9
投票
好吧,随着列表的增长,它会阻止您偶尔复制列表中的值(如果元素类型是引用类型,则这些值将是引用)。

如果它是一个特别大的列表,并且您对大小有很好的了解,那么这不会有什么坏处。但是,如果估计大小涉及额外的计算或任何大量的代码,我不会担心它,除非您发现它成为一个问题 - 它可能会分散代码的主要焦点,并且调整大小不太可能导致性能除非列表非常大或者您做了很多次,否则会出现问题。

© www.soinside.com 2019 - 2024. All rights reserved.