List<T>
的集合大小?
编辑:进一步讨论这个问题,在阅读第一个答案后,这个问题实际上可以归结为什么是默认容量以及如何执行增长操作,它是否使容量加倍等?
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
是浪费。
如果集合的大小可以 估计,指定初始 容量消除了需要 执行多次调整大小 添加元素时的操作 列表(T)。
如果它是一个特别大的列表,并且您对大小有很好的了解,那么这不会有什么坏处。但是,如果估计大小涉及额外的计算或任何大量的代码,我不会担心它,除非您发现它成为一个问题 - 它可能会分散代码的主要焦点,并且调整大小不太可能导致性能除非列表非常大或者您做了很多次,否则会出现问题。