Понимание размера объекта CLR между 32-битным и 64-битным

Я пытаюсь понять разницу размеров объектов между 32-битными и 64-битными процессорами. Допустим, у меня есть простой класс

class MyClass   
{  
    int x;  
    int y;  
}  

Итак, на 32-битной машине целое число составляет 4 байта. Если я добавлю в него Syncblock (еще 4 байта), размер объекта будет 12 байтов. Почему он показывает 16 байтов?

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  

На 64-битной машине целое число еще 4 байта, единственное, что изменилось, это то, что Syncblock будет 8 байтов (в качестве указателей 8 бит на 64-битных машинах). что означает, что размер объекта будет 16 байтов. Почему он показывает 24 байта?

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  

Ответы

Ответ 1

CLR может свободно размещать объекты в памяти по своему усмотрению. Это деталь реализации. Вы не должны полагаться на какой-либо конкретный макет.

Разница, которую вы видите, связана с отсутствием поля TypeHandle, которое также является частью заголовка объекта CLR. Кроме того, поля могут быть выровнены с границами байтов.


От Продвинутая .Net-отладка - Внутренняя структура объектов CLR:

Внутренняя структура CLR объектов:

[DWORD: SyncBlock] [DWORD: MethodTable Pointer] [DWORD: указатель ссылочного типа]... [Значение поля Тип значения]...

Заголовок объекта: [DWORD: SyncBlock]
Указатель объекта: [DWORD: MethodTable Pointer] [DWORD: указатель ссылочного типа]... [Значение поля Тип значения]...

Каждому объекту предшествует ObjHeader (с отрицательным смещением). ObjHeader имеет индекс для SyncBlock.


Итак, ваш объект, скорее всего, выложен следующим образом:

x86: (согласовано с 8 байтами)

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

x64: (соответствует 8 байтам)

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

См. также: Сверлить внутри .NET Framework Internals, чтобы узнать, как среда CLR создает объекты выполнения

Ответ 2

Блок синхронизации находится на отрицательном смещении от указателя объекта. Первое поле со смещением 0 - указатель таблицы методов, 8 байтов на x64. Итак, на x86 это SB + MT + X + Y = 4 + 4 + 4 + 4 = 16 байт. Индекс блока синхронизации по-прежнему составляет 4 байта в x64. Но заголовок объекта также участвует в сборнике мусора, действуя как node в связанном списке после его выпуска. Для этого требуется обратный и прямой указатель, каждый 8 байтов в x64, что требует 8 байтов до указателя объекта. 8 + 8 + 4 + 4 = 24 байта.

Ответ 3

У объектов есть некоторые накладные расходы за пределами переменных-членов. В 32-разрядных реализациях .NET накладные расходы на распределение составляют 12 байтов. Как я помню, это 16 байт в 64-битной среде выполнения.

Кроме того, выделение объектов выравнивается на следующей границе 8 байтов.

Ответ 4

Кажется, у любого объекта должен быть какой-то указатель на его класс. Это будет учитывать ваши дополнительные 4 или 8 байтов.

Однако макет объекта действительно является реализацией. Если вы заботитесь о макете, есть атрибуты, предназначенные для явного указания .net где и как вы хотите, чтобы элементы были расположены. Проверьте StructLayoutAttribute.