Страницы

Поиск по вопросам

четверг, 20 декабря 2018 г.

Поведение сборщика мусора по отношению к структурам

Недавно прочитал статью Предельная производительность: C# Из-за того, что структуры хранятся в stack’е, они не требуют сборки мусора поясните пожалуйста, это действительно так?


Ответ

Краткое содержание. Нет, структуры не обязательно хранятся в стеке, а объекты -- в куче. Да, с хорошими шансами структура всё же попадёт в стек. Нет, вам не стоит на это рассчитывать, пользоваться этим и пытаться оптимизировать таким образом. На самом деле следует понимать простую вещь: выделение переменной на стеке дешевле, поскольку её можно легко уничтожить, не включая в цикл сборки мусора. Выгода на самом деле только в этом. (Аллокация что на стеке, что в куче -- не более, чем увеличение одного указателя, она очень быстрая.) Очевидно, оптимизатор будет размещать в стеке те переменные, которые, как он может доказать, не нужны после смерти текущего фрейма. Часто про структуры можно такое доказать, но не всегда. Например, структура может быть частью объекта класса, и должна умереть вместе с классом. Или метод будет неявно переписан в стиле продолжений, например, если это генератор (yield return & Co.) или Task<> с async/await. Или переменная попала в замыкание некоторой лямбда-функции. И так далее. Но обычно структуры не нужны после отработки метода, так что оптимизатор может вытеснить их в стек. С другой стороны, про некоторые объекты можно тоже утверждать, что они не нужны после окончания фрейма -- и тогда оптимизатор тоже имеет полное право (но не обязанность, конечно) разместить и их на стеке. Обратите внимание на такую тонкость: если вы возвращаете из метода структуру, вы на самом деле возвращаете её копию, поэтому структура, с которой вы работали, может попасть в стек. С классами же не так: они копируются не по значению, а по ссылке, поэтому возвращаемый объект переживает создавшую его функцию, и следовательно не имеет права жить в стеке. Использованы материалы из блога Эрика Липперта, на которые была ссылка выше. Добавлю ещё пару цитат из Эрика: Использование стека для локальных переменных-структур -- всего лишь оптимизация, которую CLR выполняет для вас. Существенная особенность структур -- семантика копирования по значению, а вовсе не то, что в некоторых случаях их уничтожение может быть оптимизировано рантайм-библиотекой. В подавляющем большинстве программ, выделение и уничтожение локальных переменных не будут критически важным фактором производительности. Превращение типа, который должен на самом деле быть ссылочным типом, в структуру -- это нано-оптимизация, дающая выгоду в пару наносекунд, и вероятно не стоящая того. На вашем месте я бы проводил такую оптимизацию только если данные профилирования покажут, что существует реальная, большая проблема у ваших реальных клиентов, которую можно исправить использованием структур. Не имея таких данных на руках, я всегда бы делал выбор между классами и структурами основываясь на том, представляет ли тип семантически значение или ссылку на что-то. (То есть, имеет ли объект смысл помимо значения, содержащегося в нём, обладает ли он самостоятельной сущностью -- VladD)

Комментариев нет:

Отправить комментарий