是否值得初始化List <T>的集合大小,如果它的大小合理地知道?

Chr*_*sic 35 c# generics list

List<T>如果合理地知道它的初始化是否值得?

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

Han*_*ant 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进行炸弹.通常在消耗所有可用虚拟内存之前.

简而言之,通过提前设置容量,在开始填充List之前,您可以预先保留大型内部阵列.你不会在大对象堆中获得所有那些笨拙的释放块并避免碎片.实际上,您将能够在列表中存储更多对象,并且您的程序运行更精简,因为垃圾很少.只有当你清楚知道列表的大小时才这样做,使用你永远不会填充的大容量是浪费.

  • 非常丰富的答案,我认为我不必使用超过10,000个元素的列表,但现在如果我认为我将需要这些知识将非常有用于理解列表的含义. (2认同)

Asa*_*sad 19

根据文件,它是

如果可以估计集合的大小,则指定初始容量消除了在向List(T)添加元素的同时执行大量调整大小操作的需要.


Jon*_*eet 8

好吧,它会阻止你列表中的值(如果元素类型是引用类型将是引用),随着列表的增长不得不偶尔复制.

如果它是一个特别大的列表,你已经很好地了解它的大小,它不会受到伤害.但是,如果估计大小涉及额外的计算或任何大量的代码,我不会担心它,除非你发现它成为一个问题 - 它可能会分散代码的主要焦点,并且调整大小不太可能导致性能问题,除非它是一个非常重要的列表,或者你正在做很多事情.