16

32ビットプロセッサと64ビットプロセッサのオブジェクトサイズの違いを理解しようとしています。簡単なクラスがあるとしましょう

class MyClass   
{  
    int x;  
    int y;  
}  

したがって、32ビットマシンでは、整数は4バイトです。Syncblockを追加すると(さらに4バイト)、オブジェクトサイズは12バイトになります。なぜ16バイトを表示しているのですか?

0:000>!do 0x029d8b98  
名前:ConsoleApplication1.Program + MyClass  
MethodTable:000e33b0  
EEClass:000e149c  
サイズ:16(0x10)バイト  
 (C:\ MyTemp \ ConsoleApplication1 \ ConsoleApplication1 \ bin \ x86 \ Debug \ ConsoleApplication1.exe)  
田畑:  
      MTフィールドオフセットタイプVT属性値名  
71972d70 4000003 4System.Int321インスタンス0x  
71972d70 4000004 8System.Int321インスタンス0y  

64ビットマシンでは、整数は4バイトのままですが、変更されるのはSyncblockが8バイトになることだけです(64ビットマシンではポインターが8バイトであるため)。つまり、オブジェクトサイズは16バイトになります。なぜ24バイトを表示しているのですか?

0:000>!do 0x00000000028f3c90  
名前:ConsoleApplication1.Program + MyClass  
メソッドテーブル:000007ff00043af8  
EEClass:000007ff00182408  
サイズ:24(0x18)バイト  
 (C:\ MyTemp \ ConsoleApplication1 \ ConsoleApplication1 \ bin \ Debug \ ConsoleApplication1.exe)  
田畑:  
              MTフィールドオフセットタイプVT属性値名  
000007fef4edd998 4000003 8System.Int321インスタンス0x  
000007fef4edd998 4000004 cSystem.Int321インスタンス0y  
4

4 に答える 4

26

CLRは、適切と思われるオブジェクトをメモリ内に自由にレイアウトできます。これは実装の詳細です。特定のレイアウトに依存しないでください。

表示される違いは、CLRオブジェクトヘッダーの一部でもあるTypeHandleフィールドが欠落しているためです。さらに、フィールドはバイト境界に揃えることができます。


Advanced .Net Debuggingから-CLRオブジェクトの内部構造

オブジェクトのCLR内部構造は次のとおりです。

[DWORD:SyncBlock] [DWORD:MethodTableポインター] [DWORD:参照型ポインター]…[値型フィールドの値]…</ p>

オブジェクトヘッダー: [DWORD:SyncBlock]
オブジェクトポインター: [DWORD:MethodTableポインター] [DWORD:参照型ポインター]…[値型フィールドの値]…</ p>

すべてのオブジェクトの前には、(負のオフセットで)ObjHeaderがあります。ObjHeaderにはSyncBlockへのインデックスがあります。


したがって、オブジェクトは次のようにレイアウトされている可能性があります。

x86 :( 8バイトに揃えて)

  Syncblk TypeHandle XY
------------、------------ | ------------、----------- -|
                         8 16

x64 :( 8バイトに揃えて)

         Syncblk TypeHandle XY
------------------------- | ------------------------ -| ------------、------------ |
                         8 16 24

参照:.NET Frameworkの内部にドリルインして、CLRがランタイムオブジェクトを作成する方法を確認する

于 2010-09-28T17:06:28.957 に答える
9

同期ブロックは、オブジェクト ポインターから負のオフセットにあります。オフセット 0 の最初のフィールドはメソッド テーブル ポインターで、x64 では 8 バイトです。x86 では、SB + MT + X + Y = 4 + 4 + 4 + 4 = 16 バイトです。同期ブロック インデックスは、x64 ではまだ 4 バイトです。ただし、オブジェクト ヘッダーはガベージ コレクション ヒープにも参加し、解放された後はリンク リスト内のノードとして機能します。これには、バック ポインターとフォワード ポインターが必要で、x64 ではそれぞれ 8 バイトであるため、オブジェクト ポインターの前に 8 バイトが必要です。8 + 8 + 4 + 4 = 24 バイト。

于 2010-09-28T18:05:39.773 に答える
0

オブジェクトには、メンバー変数を超えるオーバーヘッドがあります。.NET の 32 ビット実装では、割り当てオーバーヘッドは 12 バイトのようです。思い出したように、64 ビット ランタイムでは 16 バイトです。

さらに、オブジェクトの割り当ては、次の 8 バイト境界に配置されます。

于 2010-09-28T17:09:50.113 に答える
0

私には、どのオブジェクトもそのクラスへの何らかのポインタを持つべきだと思われます。これは、余分な 4 または 8 バイトの原因になります。

ただし、オブジェクトのレイアウトは実際には実装の問題です。レイアウトが気になる場合は、メンバーを配置する場所と方法を .net に明示的に伝えるように設計された属性があります。StructLayoutAttributeを確認してください。

于 2010-09-28T17:11:56.387 に答える