列出具有初始容量的内存分配

本文关键字:容量 内存 分配 列出 | 更新日期: 2023-09-27 18:30:50

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

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

由于X大于 36,000 个元素,因此我正在尝试最大程度地减少不必要的内存分配,如果可以避免的话,我不想为一个List分配两次。 我的理解是分配的大小(36k 元素 * 4B 引用 ~= 144kB)将分配推到大堆上。 雪上加霜的是,我有一个包含大约 4,000 个元素的Dictionary<key, List<foo>>

我的问题:

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

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


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

.NET 中集合的内存分配 - 因为它们不初始化此问题中的List<T>

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

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

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

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

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

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

实现是这样的:

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