列出<t>具有初始容量的内存分配</t>

时间:2013-09-09 15:04:33

标签: c# memory-management collections

我试图了解C#.NET 4.0 List<T>(initSize)如何分配内存。

我的问题是我有一个List<foo>,其中类foo需要至少20个字节的内存。我有两种情况,我最终会XX+60 foo元素。我不知道在分配时间它会是哪两种情况。

由于X大于36,000个元素,我正在尝试最小化不必要的内存分配,如果可以避免,我不想为一个List分配两次。我的理解是分配的大小(36k元素* 4B引用〜= 144kB)推动大堆上的分配。令我不安的是,我有Dictionary<key, List<foo>>,大约有4,000个元素。

我的问题:

  1. C#运行时是否分配超出初始指定容量的数量?例如,如果我初始化为36,000个条目,我是否真的分配了65,536个条目,因为那是2的下一个大于36,000的幂?

  2. 我是否应该在所有情况下分配到X+60而不是X以避免第二次分配?在这种情况下,60恰好是一个不变的恒定值。


  3. 我的问题很相似,但与以下内容不同:

    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>进行了摔跤,这不是我的问题。

2 个答案:

答案 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接口定义。