2010-09-28 10 views
14

Próbuję zrozumieć różnicę wielkości obiektu między procesorami 32- i 64-bitowymi. Powiedzmy, że mam prostą klasęOpis rozmiaru obiektu CLR między 32-bitowym a 64-bitowym

Tak więc na komputerze 32-bitowym liczba całkowita wynosi 4 bajty. Jeśli dodaję do niego blok synchroniczny (kolejne 4 bajty), rozmiar obiektu wyniesie 12 bajtów. Dlaczego pokazuje 16 bajtów?

 
0:000> !do 0x029d8b98 
Name: ConsoleApplication1.Program+MyClass 
MethodTable: 000e33b0 
EEClass: 000e149c 
Size: 16(0x10) bytes 
(C:\MyTemp\ConsoleApplication1\ConsoleApplication1\bin\x86\Debug\ConsoleApplication1.exe) 
Fields: 
     MT Field Offset     Type VT  Attr Value Name 
71972d70 4000003  4   System.Int32 1 instance  0 x 
71972d70 4000004  8   System.Int32 1 instance  0 y 

Na komputerze 64 bitowym liczbą całkowitą jest jeszcze 4 bajty jedyną rzeczą jest to, że zmieniły Syncblock będzie 8 bajtów (jako wskaźniki są 8 bajtów na 64 maszynach bit). oznacza to, że rozmiar obiektu wynosi 16 bajtów. Dlaczego pokazuje 24 bajty?

 
0:000> !do 0x00000000028f3c90 
Name: ConsoleApplication1.Program+MyClass 
MethodTable: 000007ff00043af8 
EEClass: 000007ff00182408 
Size: 24(0x18) bytes 
(C:\MyTemp\ConsoleApplication1\ConsoleApplication1\bin\Debug\ConsoleApplication1.exe) 
Fields: 
       MT Field Offset     Type VT  Attr   Value Name 
000007fef4edd998 4000003  8   System.Int32 1 instance    0 x 
000007fef4edd998 4000004  c   System.Int32 1 instance    0 y 

Odpowiedz

24

CLR może dowolnie układać obiekty w pamięci. To szczegół implementacji. Nie powinieneś polegać na żadnym konkretnym układzie.

Różnica, którą widzisz, wynika z brakującego pola TypeHandle, które jest również częścią nagłówka obiektu CLR. Dodatkowo pola mogą być wyrównane do granic bajtów.


Od Advanced .Net Debugging - CLR Object’s Internal Structure:

CLR struktura wewnętrzna obiektu jest:

[DWORD: SyncBlock] [DWORD: MethodTable Pointer] [DWORD: Wniosek typ wskaźnik] ... [Wartość Wartość typ pola] ...

Object Header: [DWORD: SyncBlock]
Wskaźnik obiektu: [DWORD: Wskaźnik MethodTable] [DWORD: Wskaźnik typu odniesienia] ... [Pole wartości typu wartości] ...

Każdy obiekt jest poprzedzony przez ObjHeader (z ujemnym przesunięciem). ObjHeader ma indeks do synchronizacji.


Więc twój cel jest prawdopodobnie rozplanowany tak:

x86: (wyrównany do 8 bajtów)

 
    Syncblk  TypeHandle  X   Y 
------------,------------|------------,------------| 
         8       16 

: (wyrównany do 8 bajtów)

 
     Syncblk     TypeHandle    X   Y 
-------------------------|-------------------------|------------,------------| 
         8       16      24 

Zobacz także: Drill Into .NET Framework Internals to See How the CLR Creates Runtime Objects

0

Przedmioty jakieś napowietrznych poza zmiennymi członkowskich. W 32-bitowych implementacjach .NET obciążenie związane z przydziałem wynosi 12 bajtów. Jak pamiętam, w 64-bitowym środowisku wykonawczym jest to 16 bajtów.

Ponadto przydziały obiektów są wyrównane na następnej granicy 8 bajtów.

+0

Wyrównany lub nie, rozmiar powinien nadal odzwierciedlać rzeczywisty rozmiar obiektu. Wypełnienie będzie liczone tylko do rozmiaru, jeśli jest pomiędzy członkami, co nie ma miejsca w tym przypadku. – cHao

+0

Szczegóły dotyczące jakiegokolwiek narzutu na zewnątrz obiektu nie są w tym przypadku istotne. Większość tego obciążenia znajduje się w tabelach obiektów w środowisku wykonawczym, a nie w obiekcie. – cHao

0

Wydaje mi się, że każdy obiekt powinien mieć wskaźnik dla swojej klasy. To by uwzględniało dodatkowe 4 lub 8 bajtów.

Układ obiektu jest jednak naprawdę rzeczą wykonawczą. Jeśli zależy Ci na układzie, istnieją atrybuty przeznaczone do jawnego informowania .net gdzie i jak chcesz ustawić członków. Sprawdź StructLayoutAttribute.

7

Blok synchronizacji znajduje się w ujemnym przesunięciu względem wskaźnika obiektu. Pierwsze pole w offsecie 0 jest wskaźnikiem tablicy metod, 8 bajtów na x64. Tak więc na x86 jest to SB + MT + X + Y = 4 + 4 + 4 + 4 = 16 bajtów. Indeks bloków synchronizacji nadal wynosi 4 bajty na x64. Ale nagłówek obiektu również uczestniczy w stadzie zbierającym śmieci, działając jako węzeł na połączonej liście po jego zwolnieniu. Wymaga to wskaźnika wstecznego i do przodu, po 8 bajtów w x64, co wymaga 8 bajtów przed wskaźnikiem obiektu. 8 + 8 + 4 + 4 = 24 bajty.

Powiązane problemy