Ваш принятый ответ неверен.
Разница между типами значений и ссылочными типами в основном заключается в семантике присваивания. Типы значений копируются при присваивании - для структуры, что означает копирование содержимого всех полей. Типы ссылок только копируют ссылку, а не данные. Стек - это деталь реализации. В спецификации CLI ничего не говорится о том, где расположен объект, и плохая идея полагаться на поведение, которого нет в спецификации.
Типы значений характеризуются семантикой передачи по значению, но это не означает, что они фактически копируются сгенерированным машинным кодом.
Например, функция, которая возводит в квадрат комплексное число, может принимать действительные и мнимые компоненты в двух регистрах с плавающей запятой и возвращать свой результат в двух регистрах с плавающей запятой. Генератор кода оптимизирует все копирование.
Несколько человек объяснили, почему этот ответ был неправильным в комментариях под ним, но какой-то модератор удалил их все.
Временные объекты (местные жители) будут жить в поколении GC 0. GC уже достаточно умен, чтобы освободить их, как только они выйдут из области видимости. Для этого вам не нужно переключаться на экземпляры структуры.
Это полная чушь. GC видит только информацию, доступную во время выполнения, и к этому моменту все понятия области исчезли. GC не будет собирать ничего «как только выйдет за рамки». GC заберет его в какой-то момент после того, как он станет недоступным.
Изменяемые типы значений уже имеют тенденцию приводить к ошибкам, потому что трудно понять, когда вы изменяете копию и оригинал. Но введение ссылочных свойств в эти типы значений, как в случае с беглым интерфейсом, может привести к путанице, потому что может показаться, что некоторые части структуры копируются, а другие нет (т.е. вложенные свойства эталонные свойства). Я не могу рекомендовать против этой практики достаточно сильно, это может привести к всевозможным головным болям обслуживания в долгосрочной перспективе.
Опять же, это полная чушь. Нет ничего плохого в наличии ссылок внутри типа значения.
Теперь, чтобы ответить на ваш вопрос:
Все ли типы значений CLR, включая определяемые пользователем структуры, живут исключительно в стеке оценки, что означает, что их никогда не потребуется возвращать сборщику мусора, или есть случаи, когда они собираются мусором?
Типы значений определенно не «живут исключительно в стеке оценки». Предпочтение отдается их хранению в регистрах. При необходимости они будут пролиты в стек. Иногда их даже складывают в кучу.
Например, если вы напишите функцию, которая зацикливается на элементах массива, то есть большая вероятность, что переменная цикла int
(тип значения) будет полностью жить в регистре и никогда не будет пролита в стек или записано в кучу. Вот что имел в виду Эрик Липперт (из команды Microsoft C #, который написал о себе «Я не знаю всех подробностей» относительно GC .NET), когда писал, что типы значений могут передаваться в стек когда "джиттер выбирает не регистрировать значение" . Это также верно для типов больших значений (например, System.Numerics.Complex
), но существует большая вероятность того, что типы больших значений не поместятся в регистры.
Еще один важный пример, когда типы значений не находятся в стеке, - это когда вы используете массив с элементами типа значения. В частности, .NET Dictionary
коллекция использует массив структур для хранения ключа, значения и хэша для каждой записи в памяти. Это значительно улучшает локальность памяти, эффективность кэширования и, следовательно, производительность. Типы значений (и обобщенные обобщенные значения) являются причиной того, что .NET в 17 раз быстрее, чем Java на в этом тесте хэш-таблицы .
Я провел небольшой эксперимент, чтобы увидеть, в чем разница в сгенерированном CIL ...
CIL - это промежуточный язык высокого уровня, и, следовательно, он не даст вам никакой информации о распределении регистров и разливе в стек и даже не даст вам точную картину бокса. Однако, взглянув на CIL, вы сможете увидеть, как внешний компилятор C # или F # блокирует некоторые типы значений, так как он переводит даже конструкции более высокого уровня, такие как async и comp понять, в CIL.
Для получения дополнительной информации о сборке мусора я настоятельно рекомендую Справочник по сборке мусора и Справочник по управлению памятью . Если вы хотите глубоко погрузиться во внутреннюю реализацию типов значений в виртуальных машинах, то я рекомендую прочитать исходный код моего проекта HLVM . В HLVM кортежи являются типами значений, и вы можете увидеть сгенерированный ассемблер и то, как он использует LLVM для хранения полей типов значений в регистрах, когда это возможно, и оптимизирует ненужное копирование, выполняя в стек только при необходимости.