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之前,您可以预先保留大型内部阵列.你不会在大对象堆中获得所有那些笨拙的释放块并避免碎片.实际上,您将能够在列表中存储更多对象,并且您的程序运行更精简,因为垃圾很少.只有当你清楚知道列表的大小时才这样做,使用你永远不会填充的大容量是浪费.
好吧,它会阻止你列表中的值(如果元素类型是引用类型将是引用),随着列表的增长不得不偶尔复制.
如果它是一个特别大的列表,你已经很好地了解它的大小,它不会受到伤害.但是,如果估计大小涉及额外的计算或任何大量的代码,我不会担心它,除非你发现它成为一个问题 - 它可能会分散代码的主要焦点,并且调整大小不太可能导致性能问题,除非它是一个非常重要的列表,或者你正在做很多事情.