.NET за кулисами: что хранит объект? - PullRequest
8 голосов
/ 06 апреля 2011

Наивная система типов будет хранить объекты как указатель на свой тип (который содержит много полезной информации, например, vtable, размер объекта и т. Д.), За которым следуют его данные.Если бы в .Net была такая система типов, object занимал бы 4 байта в 32-битной системе и 8 байтов в 64-битной.

Мы можем видеть, что это не .Накладные расходы на объект составляют два размера указателя, плюс есть «минимальный» размер еще одного размера указателя.

Так что же на самом деле хранит object в нем, за кулисами?

Ответы [ 2 ]

7 голосов
/ 06 апреля 2011

Да, вот как это выглядит. 'Дескриптор типа', он же 'указатель таблицы методов', находится по смещению 0, данные объекта следуют по смещению 4. В смещении 4 есть дополнительное поле, называемое 'syncblock'. Он существует потому, что он также участвует в куче, собираемой мусором, когда пространство объектов не используется, двойной список свободных блоков, требующий двух указателей. Чтобы не тратить время впустую, у синхблока есть несколько применений, таких как сохранение состояния блокировки, хеш-код, указатель на явный синхроблок, когда нужно хранить слишком много.

Наименьший возможный объект предназначен для байта в штучной упаковке, 4 + 4 + 1 = 9 байтов. Но гранулярность выделения для кучи GC составляет 4 байта, поэтому вы получите следующее кратное 4, 12 байтов.

Это все хорошо видно с помощью отладчика в Visual Studio. Вы найдете подсказки в этом ответе .

5 голосов
/ 06 апреля 2011

(Это все из Microsoft Shared Source CLI ; он имеет исходный код CLR.)

Если вы посмотрите на clr\src\vm\object.h, вы увидите:

// The generational GC requires that every object be at least 12 bytes in size.
#define MIN_OBJECT_SIZE     (2*sizeof(BYTE*) + sizeof(ObjHeader))

, что довольно очевидно. Кроме того, в clr\src\vm\gcscan.cpp вы можете увидеть такие утверждения, как

_ASSERTE(g_pObjectClass->GetBaseSize() == MIN_OBJECT_SIZE);

или

_ASSERTE(totalSize < totalSize + MIN_OBJECT_SIZE);

, который, я думаю, объясняет, почему вы видите неожиданные размеры объектов. :)


Обновление:

@ Ганс отлично показал себя в блоке синхронизации; Я просто хочу указать на тонкость, задокументированную снова в object.h:

/* Object
 *
 * This is the underlying base on which objects are built. The MethodTable
 * pointer and the sync block index live here. The sync block index is actually
 * at a negative offset to the instance. See syncblk.h for details.
 */

class Object
{
    protected:
        MethodTable*    m_pMethTab;
    //No other fields shown here!
};

Обратите внимание на эту часть:

Индекс блока синхронизации фактически имеет отрицательное смещение к экземпляру.

Таким образом, блок синхронизации, по-видимому, на самом деле не следует таблице методов (как упоминал Ханс), но он приходит до этого - так что это не «нормальная» часть объект (из-за отсутствия лучшего слова).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...