45

.NET 配列のメモリ レイアウトとは何ですか?

たとえば、次の配列を取ります。

Int32[] x = new Int32[10];

配列の大部分が次のようなものであることを理解しています。

0000111122223333444455556666777788889999

各文字は 1 バイトで、数字は配列のインデックスに対応します。

さらに、型参照とすべてのオブジェクトの syncblock-index があることを知っているので、上記をこれに合わせて調整できます。

ttttssss0000111122223333444455556666777788889999
        ^
        +- object reference points here

さらに、配列の長さを保存する必要があるため、おそらく次のほうが正しいでしょう。

ttttssssllll0000111122223333444455556666777788889999
        ^
        +- object reference points here

これで完了ですか?配列にさらにデータがありますか?

私が尋ねている理由は、かなり大きなデータコーパスのいくつかの異なるメモリ内表現がどれだけのメモリを必要とするかを見積もろうとしているからです.配列のサイズはかなり異なります.一方のソリューションでは大きな影響がありますが、もう一方のソリューションではおそらくそれほど影響はありません。

基本的に、配列の場合、どのくらいのオーバーヘッドがあるか、それが基本的に私の質問です。

そして、配列が悪い分隊が目覚める前に、解決策のこの部分は静的な一度だけ参照されるタイプのものであるため、ここでは成長可能なリストを使用する必要はありません。

4

4 に答える 4

20

これを調べる 1 つの方法は、WinDbg のコードを調べることです。以下のコードを基に、ヒープにどのように表示されるか見てみましょう。

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

最初に行うことは、インスタンスを見つけることです。でこれをローカルにした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

これは、10 要素で合計サイズが 52 バイトの Int32 配列であることを示しています。

インスタンスが配置されているメモリをダンプしましょう。

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 バイトに括弧を挿入しました。

  • 最初の 4 バイトは、01309584 のメソッド テーブルへの参照です。
  • 次に、配列の長さの 4 バイト。
  • それに続くのは、0 から 9 の数字 (それぞれ 4 バイト) です。
  • 最後の 4 バイトはヌルです。完全にはわかりませんが、インスタンスがロックに使用されている場合、syncblock 配列への参照が格納されている場所に違いないと思います。

編集:最初の投稿で長さを忘れました。

romkyns が指摘するように、インスタンスは実際にはアドレス - 4 から始まり、最初のフィールドは Syncblock であるため、リストは少し間違っています。

于 2009-01-28T12:21:17.207 に答える
7

素晴らしい質問です。値型と参照型の両方のブロック図を含むこの記事を見つけました。Ritcher が次のように述べているこの記事も参照してください。

[中略] 各配列には、関連する追加のオーバーヘッド情報があります。この情報には、配列のランク (次元数)、配列の各次元の下限 (ほとんど常に 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 は 2 番目の次元の長さ、次に 2 つのゼロ?、その後にすべての要素が順番に続き、最後に再びゼロが続きます。

オブジェクト配列は整数配列として扱われ、内容は今回の参照です。ジャグ配列は、参照が他の配列を指すオブジェクト配列です。

于 2009-01-28T12:03:24.123 に答える
0

配列オブジェクトは、次元数と各次元の長さを格納する必要があります。したがって、モデルに追加するデータ要素が少なくとも 1 つ以上あります

于 2009-01-28T11:14:03.380 に答える