3

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

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

由于大于 36,000 个元素,因此我试图尽量减少不必要的内存分配,如果可以避免的话X,我不想为一个分配两次。List我的理解是分配的大小(36k 个元素 * 4B 参考 ~= 144kB)将分配推到大堆上。更让我烦恼的是,我有一个Dictionary<key, List<foo>>大约 4,000 个元素。

我的问题:

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

  2. 我应该X+60在所有情况下都分配给而不是X避免第二次分配吗?在这种情况下,60 恰好是一个不会变化的常数值。


我的问题类似,但与以下问题不同:

.NET 中集合的内存分配 - 因为它们没有List<T>在这个问题中初始化。

集合类型的初始容量,例如字典、列表 - 是指定初始容量的实现问题。

如何将 List<T> 初始化为给定大小(而不是容量)?- 似乎正在与Arrayvs搏斗List<T>,这不是我的问题。

4

2 回答 2

4

编译器不分配任何东西。分配发生在运行时。工作方式List<T>是它会T[]根据需要将其内部大小加倍。如果您指定初始大小,它将根据需要分配该大小并从那里加倍。

请记住,因为Tis class 在您的示例中,该列表仅包含引用。即只有当您有超过 85000 字节的引用(加上列表本身的开销)时,才会在 LOH 上分配列表。

此外,由于列表不foo包含多余空间的实例,因此仅用于引用。

于 2013-09-09T15:10:20.393 回答
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 接口定义的。

于 2013-09-09T15:11:20.233 回答