Каждый нестроковый нестроковый объект, хранящийся в куче, содержит 8- или 16-байтовый заголовок (размеры для 32/64-битных систем), за которым следует содержимое открытых и закрытых полей этого объекта. Массивы и строки имеют вышеуказанный заголовок, плюс еще несколько байтов, определяющих длину массива и размер каждого элемента (и, возможно, количество измерений, длину каждого дополнительного измерения и т. Д.), За которыми следуют все поля первого элемент, затем все поля второго и т. д. При наличии ссылки на объект система может легко проверить заголовок и определить его тип.
Места хранения ссылочного типа содержат значение в четыре или восемь байтов, которое однозначно идентифицирует объект, хранящийся в куче. В существующих реализациях это значение является указателем, но его проще (и семантически эквивалентно) представить как «идентификатор объекта».
Места хранения типа значения содержат содержимое полей типа значения, но не имеют никакого связанного заголовка. Если код объявляет переменную типа Int32
, нет необходимости хранить информацию с этим Int32
, говоря, что это такое. Тот факт, что это местоположение содержит Int32
, эффективно сохраняется как часть программы, поэтому его не нужно хранить в самом местоположении. Это представляет большую экономию, если, например, один имеет миллион объектов, каждый из которых имеет поле типа Int32
. Каждый из объектов, содержащих Int32
, имеет заголовок, который определяет класс, который может с ним работать. Поскольку одна копия кода этого класса может работать с любым из миллиона экземпляров, наличие того факта, что поле является Int32
частью кода, гораздо более эффективно, чем хранение в каждом из этих полей информации о том, что это так.
Упаковка необходима, когда делается запрос на передачу содержимого места хранения типа значения в код, который не знает, ожидать этого конкретного типа значения. Код, который ожидает объекты неизвестного типа, может принимать ссылку на объект, хранящийся в куче. Поскольку у каждого объекта, хранящегося в куче, есть заголовок, указывающий, какой это тип объекта, код может использовать этот заголовок всякий раз, когда необходимо использовать объект таким способом, который потребует знания его типа.
Обратите внимание, что в .net можно объявлять так называемые универсальные классы и методы. Каждое такое объявление автоматически генерирует семейство классов или методов, которые идентичны, за исключением того типа объекта, на который они рассчитывают воздействовать. Если передать Int32
подпрограмме DoSomething<T>(T param)
, это автоматически сгенерирует версию подпрограммы, в которой каждый экземпляр типа T
будет эффективно заменен на Int32
. Эта версия подпрограммы будет знать, что каждое место хранения, объявленное как тип T
, содержит Int32
, так что, как и в случае, когда подпрограмма жестко запрограммирована на использование места хранения Int32
, в этом нет необходимости. хранить информацию о типе в самих этих местах.