.NET数组的内存布局

ang*_*son 41 .net arrays overhead

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

以这个数组为例:

Int32[] x = new Int32[10];
Run Code Online (Sandbox Code Playgroud)

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

0000111122223333444455556666777788889999
Run Code Online (Sandbox Code Playgroud)

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

另外,我知道所有对象都有一个类型引用和一个syncblock-index,所以上面的内容可以调整为:

ttttssss0000111122223333444455556666777788889999
        ^
        +- object reference points here
Run Code Online (Sandbox Code Playgroud)

另外,需要存储数组的长度,所以这可能更正确:

ttttssssllll0000111122223333444455556666777788889999
        ^
        +- object reference points here
Run Code Online (Sandbox Code Playgroud)

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

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

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

数组坏队被唤醒之前,解决方案的这一部分是静态构建 - 一次引用 - 通常类型的事情,因此这里不需要使用可增长列表.

Bri*_*sen 19

检查这一点的一种方法是查看WinDbg中的代码.因此,考虑到下面的代码,让我们看看它是如何出现在堆上的.

var numbers = new Int32[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Run Code Online (Sandbox Code Playgroud)

首先要做的是找到实例.由于我已将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
Run Code Online (Sandbox Code Playgroud)

这告诉我们我们的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  .$@.............
Run Code Online (Sandbox Code Playgroud)

我插入了52个字节的括号.

  • 前四个字节是01309584处方法表的引用.
  • 然后是阵列长度的四个字节.
  • 之后是数字0到9(每四个字节).
  • 最后四个字节为空.我不完全确定,但我想这必须是在实例用于锁定时存储对syncblock数组的引用的地方.

编辑:首次发布时忘记长度.

列表略有不正确,因为romkyns指出实例实际上从地址-4开始,第一个字段是Syncblock.

  • 最后四个字节实际上位于该数组之外。这是因为你得到的指针在对象中偏移了4;同步块索引首先位于偏移量 -4 处。[参考](http://msdn.microsoft.com/en-us/magazine/cc163791.aspx) (4认同)

ng5*_*000 7

好问题.我发现这篇文章包含值类型和引用类型的框图.另见Ritcher所述的这篇文章:

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

  • 我可以建议在此解决方案中添加Code Project的"Arrays UNDOCUMENTED"文章:http://www.codeproject.com/KB/dotnet/arrays.aspx (2认同)
  • 那段剪辑来自的书叫做"CLR via C#",它是一本很棒的书. (2认同)

小智 6

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

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

ssssllll000011112222....nnnn0000
Run Code Online (Sandbox Code Playgroud)

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

对于多维数组:

ssssttttl1l1l2l2????????
    000011112222....nnnn000011112222....nnnn....000011112222....nnnn0000
Run Code Online (Sandbox Code Playgroud)

其中s是同步块,t是元素的总数,l1是第一维的长度,l2是第二维的长度,然后是两个零?,然后是所有元素的顺序,最后再次为零.

对象数组被视为整数数组,这次内容是引用.锯齿状数组是对象数组,其中引用指向其他数组.