【问题标题】:List<object> memory overheadList<object> 内存开销
【发布时间】:2017-08-30 23:01:23
【问题描述】:

我有这样的事情:

List<object> res = new List<object>();
...
while (...)
{
   byte[] val = //get new byte[4]
   res.Add(val); //if this is commented memory usage goes from 2Gb to 180Mb
}

return res;

现在val 始终是字节[4],大约有 37000000 个元素。所以我认为res 应该在 37*10^6 * 4 bytes = 148 MB 左右,但实际内存使用量在 2GB 左右。如果我评论res.Add(val);,那么内存使用量大约是 100 MB。

那么内存去哪了?

编辑

我尝试使用 uint 代替 byte[4],但结果是一样的:

EDIT2

好的,使用 uint 代替 byte[4] and List&lt;uint&gt;() 代替 List&lt;object&gt; 将内存设置为 300 MB 左右。

【问题讨论】:

  • 如何计算内存使用量?任务管理器?
  • 3700 万个对象的 2 GB 减少到每个装箱值 54 个字节,包括运行时 (GC) 的簿记和一般 .NET 的开销,而且您的程序并不小,因为当它完全没有做任何事情时,您指示的占用空间为 100 MB。为什么你认为List&lt;T&gt; 是相关的?数组不显示相同的行为吗?你想解决什么问题?
  • @HimBromBeere 使用 VS 调试器,看截图
  • @CodeCaster 我只是尝试使用 new object[37000000]; 而不是 List&lt;object&gt; - 未注释它仍然是 2 Gb,注释它是 420 Mb
  • 一些简单的尝试:List&lt;byte&gt;AddRange。 (不要忘记用一些实际大小来初始化列表)。

标签: c# memory-management


【解决方案1】:

这是分配大量微小对象的常见问题:通常可以忽略的对象开销开始发挥作用。

37*10^6 * 4 字节 = 148 Mb

假设四个字节的数组将占用内存中的四个字节是不正确的。除了四个字节的有效负载外,数组对象还必须存储数组的长度、同步块和类型指针。这在 32 位系统上会产生 12 字节的开销,在 64 位系统上会产生 24 字节的开销。

除了数组对象的单独开销之外,您还需要考虑内存分配器的开销、内存对齐的开销和垃圾收集器的开销。综上所述,使用的总内存增长到 2 Gb 并非不合理。

解决此问题的一种方法是切换到uints 的列表,每个都占用四个字节。当需要存储四个字节时,将它们转换为uint,并存储在列表中。当您需要返回字节时,将uint 转换为一个临时的四字节数组。使用BitConverter处理uints和bytes的数组之间的转换。

【讨论】:

  • 嗯,出乎意料,这并没有减少内存,我在问题中放了一个截图
  • @ren 你使用List&lt;object&gt; 还是List&lt;uint&gt;?对象列表将携带“装箱”值的开销,这接近于数组的开销。 uints 列表的开销要小很多。
猜你喜欢
  • 2011-11-16
  • 2011-02-12
  • 2020-12-13
  • 2019-12-06
  • 1970-01-01
  • 1970-01-01
  • 2013-03-22
  • 2014-09-11
  • 1970-01-01
相关资源
最近更新 更多