我试图了解C#.NET 4.0 List<T>(initSize)
如何分配内存。
我的问题是我有一个List<foo>
,其中类foo
需要至少20个字节的内存。我有两种情况,我最终会X
或X+60
foo
元素。我不知道在分配时间它会是哪两种情况。
由于X
大于36,000个元素,我正在尝试最小化不必要的内存分配,如果可以避免,我不想为一个List
分配两次。我的理解是分配的大小(36k元素* 4B引用〜= 144kB)推动大堆上的分配。令我不安的是,我有Dictionary<key, List<foo>>
,大约有4,000个元素。
我的问题:
C#运行时是否分配超出初始指定容量的数量?例如,如果我初始化为36,000个条目,我是否真的分配了65,536个条目,因为那是2的下一个大于36,000的幂?
我是否应该在所有情况下分配到X+60
而不是X
以避免第二次分配?在这种情况下,60恰好是一个不变的恒定值。
我的问题很相似,但与以下内容不同:
Memory allocation for collections in .NET - 因为他们没有在此问题中初始化List<T>
。
Initial capacity of collection types, e.g. Dictionary, List - 是指定初始容量的实施问题。
How to initialize a List<T> to a given size (as opposed to capacity)? - 似乎与Array
vs List<T>
进行了摔跤,这不是我的问题。
答案 0 :(得分:4)
编译器不分配任何内容。分配在运行时发生。 List<T>
的工作方式是根据需要将内部T[]
的大小加倍。如果你指定一个初始大小,它将根据需要分配它并从那里加倍。
请记住,因为T
在您的示例中是类,所以列表仅包含引用。即当您有超过85000字节的引用(加上列表本身的开销)时,列表将仅在LOH上分配。
此外,由于列表不包含foo
的实例,因此多余空间仅用于引用。
答案 1 :(得分:4)
实施是这样的:
public List(int capacity)
{
if (capacity < 0x0)
{
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.capacity, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
}
if (capacity == 0x0)
{
this._items = List<T>._emptyArray;
}
else
{
this._items = new T[capacity];
}
}
所以它将使用确切的容量。这种情况在未来是否真实尚不确定,因为它没有由List接口定义。