列出具有初始容量的内存分配
本文关键字:容量 内存 分配 列出 | 更新日期: 2023-09-27 18:30:50
我正在尝试了解 C# .NET 4.0 List<T>(initSize)
如何分配内存。
我的问题是我有一个List<foo>
类foo
至少需要 20 字节的内存。 我有两种情况,我最终会拥有X
或X+60
foo
元素。 我不知道在分配时会是两种情况中的哪一种。
由于X
大于 36,000 个元素,因此我正在尝试最大程度地减少不必要的内存分配,如果可以避免的话,我不想为一个List
分配两次。 我的理解是分配的大小(36k 元素 * 4B 引用 ~= 144kB)将分配推到大堆上。 雪上加霜的是,我有一个包含大约 4,000 个元素的Dictionary<key, List<foo>>
。
我的问题:
-
C# 运行时分配的容量是否超出了初始指定的容量? 例如,如果我初始化为 36,000 个条目,我是否真的分配了 65,536 个条目,因为这是 2 的下一个幂大于 36,000?
-
我是否应该在所有情况下都只分配给
X+60
而不是X
以避免第二次分配? 在这种情况下,60 恰好是一个常量值,不会变化。
我的问题相似,但与以下内容不同:
.NET 中集合的内存分配 - 因为它们不初始化此问题中的List<T>
。
集合类型的初始容量,例如字典、列表 - 是指定初始容量时的实现问题。
如何将ListArray
与List<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 接口定义的。