45

.NET 数组的内存布局是什么?

以这个数组为例:

Int32[] x = new Int32[10];

我知道数组的大部分是这样的:

0000111122223333444455556666777788889999

其中每个字符是一个字节,数字对应于数组中的索引。

另外,我知道所有对象都有一个类型引用和一个同步块索引,所以上面可以调整为:

ttttssss0000111122223333444455556666777788889999
        ^
        +- object reference points here

此外,需要存储数组的长度,所以也许这更正确:

ttttssssllll0000111122223333444455556666777788889999
        ^
        +- object reference points here

这是完整的吗?数组中是否有更多数据?

我问的原因是我们试图估计一个相当大的数据语料库的几个不同的内存表示将占用多少内存,并且数组的大小变化很大,所以开销可能有在一种解决方案中影响很大,但在另一种解决方案中可能影响不大。

所以基本上,对于一个数组,有多少开销,这基本上是我的问题。

数组坏了小队醒来之前,这部分解决方案是静态构建一次引用-经常类型的东西,因此这里不需要使用可增长列表。

4

4 回答 4

20

检查这一点的一种方法是查看 WinDbg 中的代码。所以给定下面的代码,让我们看看它是如何出现在堆上的。

var numbers = new Int32[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

首先要做的是找到实例。由于我已将其设为本地 in Main(),因此很容易找到实例的地址。

从地址我们可以转储实际的实例,这给了我们:

0:000> !do 0x0141ffc0
Name: System.Int32[]
MethodTable: 01309584
EEClass: 01309510
Size: 52(0x34) bytes
Array: Rank 1, Number of elements 10, Type Int32
Element Type: System.Int32
Fields:
None

这告诉我们这是我们的 Int32 数组,有 10 个元素,总大小为 52 字节。

让我们转储实例所在的内存。

0:000> d 0x0141ffc0
0141ffc0 [84 95 30 01 0a 00 00 00-00 00 00 00 01 00 00 00  ..0.............
0141ffd0  02 00 00 00 03 00 00 00-04 00 00 00 05 00 00 00  ................
0141ffe0  06 00 00 00 07 00 00 00-08 00 00 00 09 00 00 00  ................
0141fff0  00 00 00 00]a0 20 40 03-00 00 00 00 00 00 00 00  ..... @.........
01420000  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
01420010  10 6d 99 00 00 00 00 00-00 00 01 40 50 f7 3d 03  .m.........@P.=.
01420020  03 00 00 00 08 00 00 00-00 01 00 00 00 00 00 00  ................
01420030  1c 24 40 03 00 00 00 00-00 00 00 00 00 00 00 00  .$@.............

我为 52 个字节插入了括号。

  • 前四个字节是对 01309584 处方法表的引用。
  • 然后是数组长度的四个字节。
  • 接下来是数字 0 到 9(每个四个字节)。
  • 最后四个字节为空。我不完全确定,但我想如果实例用于锁定,那一定是对同步块数组的引用的存储位置。

编辑:在第一次发布时忘记了长度。

该列表有点不正确,因为正如 romkyns 指出的那样,实例实际上从地址 4 开始,第一个字段是 Syncblock。

于 2009-01-28T12:21:17.207 回答
7

好问题。我发现这篇文章包含值类型和引用类型的框图。另请参阅Ritcher 指出的这篇文章:

[snip] 每个数组都有一些与之相关的额外开销信息。此信息包含数组的等级(维数)、数组每个维的下限(几乎总是 0)以及每个维的长度。开销还包含数组中每个元素的类型。

于 2009-01-28T11:28:56.547 回答
6

好问题!我想亲眼看看,这似乎是试用 CorDbg.exe 的好机会……

似乎对于简单的整数数组,格式是:

ssssllll000011112222....nnnn0000

其中 s 是同步块,l 是数组的长度,然后是各个元素。似乎最后有一个finally 0,我不知道为什么会这样。

对于多维数组:

ssssttttl1l1l2l2????????
    000011112222....nnnn000011112222....nnnn....000011112222....nnnn0000

其中 s 是同步块,t 是元素的总数,l1 是第一维的长度,l2 是第二维的长度,然后是两个零,然后依次是所有元素,最后又是一个零。

对象数组被当作整型数组,这次是引用的内容。锯齿状数组是对象数组,其中引用指向其他数组。

于 2009-01-28T12:03:24.123 回答
0

数组对象必须存储它有多少维以及每个维的长度。所以至少还有一个数据元素要添加到您的模型中

于 2009-01-28T11:14:03.380 回答