【发布时间】:2022-01-04 11:40:51
【问题描述】:
我正在尝试将大量数据添加到列表中,但它似乎比数组使用更多的 RAM。我想知道为什么会这样,是否有更好的解决方案。
这个带有数组的解决方案需要大约 78 MB 的 RAM。有意义,因为 4 字节 * 20000000 ~= 76 MB:
float[] arrayValues = new float[20000000];
for (int i = 0; i < 20000000; i++)
arrayValues[i] = i;
但是这个带有列表的解决方案需要 206 MB (!!):
List<float> listValues = new();
for (int i = 0; i < 20000000; i++)
listValues.Add(i);
怎么可能?它基本上是在做同样的事情——保存 20000000 个浮点值。额外的 128 MB 来自哪里?有没有更好的方法不会产生这么多开销?
【问题讨论】:
-
你如何测量列表的内存使用情况?随着列表的动态增长,您的列表将需要多次调整大小 - 您是否有可能在测量中包含那些已被丢弃(但可能尚未被垃圾收集)的旧的、太小的数组?您是否尝试过为列表提供初始容量,即
new(20000000)? -
提示
var listValues = new List<float>(20000000)。 -
@Zelos
a List use almost 3x the memory of an array?它没有。List使用数组。您的代码虽然会导致内部数组的大量重新分配 -
作为一个球场,
List<T>从一个大小为 4 的数组开始,每次空间不足时将其加倍,因此对于 20000000 个元素,它会将其内部数组的大小调整大约 23 次。所以周围有 22 个左右的旧数组,大小从 4 字节到 16.8M 不等,可能还没有被回收。给列表一个初始容量可以避免所有这些,它会在开始时分配一个正确大小的数组。 -
@Someprogrammerdude 自己看:source.dot.net/#System.Private.CoreLib/List.cs,cf7f4095e4de7646,或者文档:docs.microsoft.com/en-us/dotnet/api/… -- "它通过使用一个数组来实现
IList<T>泛型接口,该数组的大小根据需要动态增加.”。它是一个列表,但不是链表,如果您对此感到困惑的话。