如果有合理的名称,是否值得初始化List<T>
的集合大小?
编辑:进一步提出这个问题,在阅读完第一个答案之后,这个问题实际上归结为默认容量是什么,增长操作是如何进行的,是否将容量增加了一倍等等。 p>
答案 0 :(得分:68)
是的,当List<T>
变大时,它变得很重要。确切的数字取决于元素类型和机器架构,让我们在32位机器上选择一个引用类型列表。然后,每个元素将在内部数组中占用4个字节。该列表将以Capacity 0和一个空数组开始。第一个Add()
调用将容量增加到4,将内部数组重新分配为16个字节。稍后四次Add()
次调用,数组已满,需要再次重新分配。它的大小翻倍,容量增加到8,数组大小增加到32个字节。前面的数组是垃圾。
如果需要,这会重复,内部数组的几个副本将变成垃圾。
当数组增长到65,536字节(16,384个元素)时会发生一些特殊情况。下一个Add()再次将大小翻倍为131,072字节。这是一个超出“大对象”(85,000字节)阈值的内存分配。现在不再在第0代堆上进行分配,而是从大对象堆中获取。
LOH上的物体是专门处理的。它们仅在第2代收集期间被垃圾收集。并且堆不会被压缩,移动这么大的块需要花费太多时间。
根据需要重复,几个LOH对象将变成垃圾。他们可以占用内存很长一段时间,第2代收藏不会经常发生。另一个问题是这些大块往往会破坏虚拟内存地址空间。
这不会无休止地重复,List类需要重新分配数组,并且它已经变得如此之大,以至于虚拟内存地址空间中没有留下任何空洞来适应数组。您的程序将使用OutOfMemoryException进行炸弹。通常在消耗所有可用虚拟内存之前。
长话短说,通过提前设置容量,在开始填充列表之前,您可以预先保留大型内部阵列。你不会在大对象堆中获得所有那些笨拙的释放块并避免碎片。实际上,您将能够在列表中存储更多对象,并且您的程序运行更精简,因为垃圾很少。只有当你清楚知道列表的大小时才这样做,使用你永远不会填充的大容量是浪费。
答案 1 :(得分:19)
如果集合的大小可以 估计,指定初始 容量消除了需要 执行一些调整大小 添加元素时的操作 清单(T)。
答案 2 :(得分:8)
好吧,它会阻止你列表中的值(如果元素类型是引用类型将是引用),随着列表的增长,必须偶尔复制它们。
如果它是一个特别大的列表,你对它的大小非常了解,那就不会受到伤害。但是,如果估计大小涉及额外的计算或任何大量的代码,我不会担心它,除非你发现它成为一个问题 - 它可能会分散代码的主要焦点,并且调整大小不太可能导致性能问题,除非它是一个非常重要的列表,或者你正在做很多事情。