【问题标题】:How are arrays handled in memory?数组在内存中是如何处理的?
【发布时间】:2016-08-30 05:24:39
【问题描述】:

鉴于数组被分配了固定的内存区域,因此数组的长度是不可变的,这完全有道理。

假设我有 Array[10] - 这将分配 10 个相邻内存插槽,对吗?这是因为这些插槽是相邻的并且在预定的位置,基于索引的查找很快。

但是,如果我将复杂类型放入我的数组中,大小不均。数组中的实际对象可能属于同一类型,但它们所保存的数据的大小可能会有很大差异。

.Net 如何处理这个问题?我想它会分配非顺序内存来存储对象中的实际数据,但我想要一个权威的答案。例如 - 如果对象超过一定大小,它是否只使用非顺序内存?如果对象的大小不断变化,它会继续尝试优化存储位置吗?

考虑这个类:

public class MyClass
{
    public MyClass[] PotentiallyHugeNestedStructure
}

现在,如果我有一个 myclass 数组并在运行时开始分配给子数组和子数组。我最终会得到大量的锯齿状数组。

那么 .net 在内存中是如何处理这个问题的呢?

【问题讨论】:

  • 数组中的实际对象 ?!不,数组包含对对象内存位置(在托管堆中)的引用,而不是对象本身!
  • @user3185569,所以它们真的只是一个顺序链表?
  • The actual objects in the array might be of the same type, but the data they hold can differ vastly in size 即使数据不同,每个索引分配的存储空间是相同的(int 4 字节),只要分配的内存可以保存为该块存储的值
  • 如果我不得不猜测,我会说锯齿状数组项目是按顺序存储的,存储的是对实际对象的引用。我真的不知道,我对答案很感兴趣
  • 数组元素总是固定大小。如果它们是引用类型,那么元素本身就是引用(x86 上为 32 位,x64 上为 64 位等)。如果它们是值类型,那么每个值的大小总是相同的,每个数组元素也是如此。

标签: c# .net


【解决方案1】:

在引用类型的数组中,数组中的每个元素都包含一个指向托管堆中对象的引用。

因此,在数组本身的大小范围内(如您指定的那样),在原始类型数组之上拥有对象数组并没有缺点(除了创建对象本身的开销之外,数组元素 reference与内存中数组的大小无关)。

在通过索引访问元素的范围内,没有区别,因为两者都是通过索引访问的。通过引用从堆中检索对象肯定会产生开销,但它非常快(因为引用通常是一个表示内存位置偏移量的数字)。

下图展示了保存引用类型的数组与保存值类型的数组:

图片来自:CLR Via C# by Jeffrey Richter

myControls 是一个对象数组,因此每个元素都包含 Null(默认情况下)或对对象的引用(32 位系统为 4 个字节,64 位系统为 8 个字节)。

旁注:图片中指定的overhead包含了数组的相关信息:

  • 维度
  • 每个维度的下限(大多数情况下为 0)
  • 数组的长度。

【讨论】:

  • "因此对象数组相对于原始类型数组绝对没有缺点。您可以通过索引以非常快速的方式访问列表中的任何对象" i>——由于各种原因,这种说法是非常不正确的。在许多情况下,值类型数组的性能明显优于引用类型数组。最大的因素之一是内存局部性及其对缓存的影响,但还有其他问题。
  • @PeterDuniho 我认为我写的内容不够清楚。我提到这是对OP所说的回复。他认为,对象数组在内存中占用的内存比原始类型数组更大,这不是必须的。也可能反过来,因为某些值类型需要比引用更多的内存。我希望编辑现在很清楚。
  • 请提供一个值类型的示例,它与等效引用类型执行相同的有效工作,比等效引用类型使用 更多 内存。
  • @PeterDuniho 如果您在内存中有 3 个具有多个字段的对象,其中一个是 decimal 字段。你需要将这 3 个字段传递给一个方法。现在让我们忘记设计决策。传递引用三个对象的数组比传递包含三个十进制字段的数组消耗更少的内存(数组本身的大小)。对吗?
  • “在这两种情况下,它都是一个单一的引用,这非常明显”——应该很明显。但是您的其他 cmets 错误地描述了数组的性质,并且在任何情况下,您都非常明确地使用了 passing 这个词,因此无论人们希望什么是显而易见的,您的陈述都是针对某人的陈述非常不明显。
猜你喜欢
  • 2020-01-08
  • 1970-01-01
  • 2015-07-07
  • 1970-01-01
  • 2015-02-26
  • 1970-01-01
  • 2012-05-28
  • 2021-09-19
  • 2018-10-04
相关资源
最近更新 更多