是否值得初始化一个 List<T> 的集合大小?如果它的大小合理地知道? [英] Is it worthwhile to initialize the collection size of a List&lt;T&gt; if it&#39;s size reasonably known?

查看:54
本文介绍了是否值得初始化一个 List<T> 的集合大小?如果它的大小合理地知道?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果List 的集合大小是合理已知的,是否值得初始化?

Is it worthwhile to initialize the collection size of a List<T> if it's reasonably known?

进一步讨论这个问题,在阅读第一个答案后,这个问题实际上归结为默认容量是多少,增长操作是如何执行的,它是否将容量加倍等?>

Furthering this question, after reading the first answers this question really boils down to what is the default capacity and how is the growth operation performed, does it double the capacity etc.?

推荐答案

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

Yes, it gets to be important when your List<T> gets large. The exact numbers depend on the element type and the machine architecture, let's pick a List of reference types on a 32-bit machine. Each element will then take 4 bytes inside an internal array. The list will start out with a Capacity of 0 and an empty array. The first Add() call grows the Capacity to 4, reallocating the internal array to 16 bytes. Four Add() calls later, the array is full and needs to be reallocated again. It doubles the size, Capacity grows to 8, array size to 32 bytes. The previous array is garbage.

根据需要重复此操作,内部数组的多个副本将成为垃圾.

This repeats as necessary, several copies of the internal array will become garbage.

当数组增长到 65,536 字节(16,384 个元素)时,会发生一些特殊情况.下一个 Add() 再次将大小加倍到 131,072 字节.这是超出大对象"阈值(85,000 字节)的内存分配.现在不再在第 0 代堆上进行分配,而是从大对象堆中进行分配.

Something special happens when the array has grown to 65,536 bytes (16,384 elements). The next Add() doubles the size again to 131,072 bytes. That's a memory allocation that exceeds the threshold for "large objects" (85,000 bytes). The allocation is now no longer made on the generation 0 heap, it is taken from the Large Object Heap.

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

Objects on the LOH are treated specially. They are only garbage collected during a generation 2 collection. And the heap doesn't get compacted, it takes too much time to move such large chunks.

这在必要时重复,几个 LOH 对象将成为垃圾.它们会占用内存很长一段时间,第 2 代收集不会经常发生.另一个问题是这些大块往往会使虚拟内存地址空间碎片化.

This repeats as necessary, several LOH objects will become garbage. They can take up memory for quite a while, generation 2 collections do not happen very often. Another problem is that these large blocks tend to fragment the virtual memory address space.

这不会无休止地重复,List 类迟早需要重新分配数组,而且它已经变得如此之大,以至于虚拟内存地址空间中没有一个洞可以容纳该数组.您的程序将使用 OutOfMemoryException 进行轰炸.通常在所有可用虚拟内存耗尽之前.

This doesn't repeat endlessly, sooner or later the List class needs to re-allocate the array and it has grown so large that there isn't a hole left in the virtual memory address space to fit the array. Your program will bomb with an OutOfMemoryException. Usually well before all available virtual memory has been consumed.

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

Long story short, by setting the Capacity early, before you start filling the List, you can reserve that large internal array up front. You won't get all those awkward released blocks in the Large Object Heap and avoid fragmentation. In effect, you'll be able to store many more objects in the list and your program runs leaner since there's so little garbage. Do this only if you have a good idea how large the list will be, using a large Capacity that you'll never fill is wasteful.

这篇关于是否值得初始化一个 List<T> 的集合大小?如果它的大小合理地知道?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆