Почему значения-типы хранятся в Stacks?

Почему С# (.Net) предпочитает стеки хранить типы значений? Какова основная причина этого дизайна? Это связано с тем, что операции чтения/записи в стек лучше использовать процессор машины?

Кроме того, может быть, вы можете обосновать, почему не другие?

Ответ 1

Эрик Липперт обсуждает этот здесь; во-первых, неверно, что "типы значений хранятся в стеке". Они иногда бывают, но не как:

  • поля класса
  • захваченные переменные
  • переменные в блоке итератора

Когда они могут быть сохранены в стеке, это удобный способ моделирования их жизни, но хранить их в стеке не требуется. Вы можете написать компилятор + CLI, который не имеет стека, например.

Ответ 2

С# ничего не хранит в стеке. С# - язык программирования. Поэтому более корректная версия вашего вопроса заключается в том, почему компилятор Microsoft С# испускает инструкции CIL для распределения типов значений в стеке?

Ну, во-первых, это только иногда. В стек не входят:

  • Типы значений, которые являются полями в классе
  • Типы в штучной упаковке
  • Типы локальных значений, которые являются внешними переменными анонимных методов.
  • Локальные типы значений, которые являются внешними переменными блоков итератора

Во-вторых, когда это возможно, это сделано, потому что оно эффективно. В основном в модели памяти CLR, при освобождении стека очень дешево относительное по сравнению с освобождением от кучи. С местными типами значений вы можете быть уверены, что никто, кроме локального, не будет ссылаться на память, чтобы вы могли избежать использования стека вместо кучи. Подробнее см. Эрик Липперт.

Наконец, особенность специальных типов заключается в том, что они имеют семантику значения типа (копирование по значению), а не то, что они иногда выделяются в стеке. В спецификации С# нет требования, чтобы компилятор выдавал инструкции для распределения типов значений в стеке. Что требует спецификация С#, так это то, что типы значений имеют семантику типа значения.

Ответ 3

Как указывает @Akash, в основном это связано с памятью. Во время разработки CLR было отмечено (моя догадка была связана с опытом Java), которые представляют собой небольшие примитивные типы, поскольку объекты с ручками, подверженными сборщику мусора, вызвали много накладных расходов на отслеживание. Поэтому дизайнерам нужен "легкий" объект, который не нужно отслеживать.

В спецификации CLI нет специфических требований для размещения пустых примитивов; это артефакт реализации на машине. Существенным является то, что среда выполнения знает, где экземпляры связаны с построением четко определенных паттернов памяти (называемых кадрами), а не в индексе GC выделенных объектов. На машинах x86 (и аналогичных) это можно эффективно использовать с помощью стека.

Ответ 4

Ваше утверждение не совсем верно. Лучшая версия: С# хранит локальные переменные в стеке.
И это не специальный или новый (почти) все языки программирования используют стек для локальных переменных и возвращаемых адресов метода. Для этого есть поддержка этого оборудования.

Кроме того, Valuetypes может быть локальными переменными или полями внутри ссылочных типов. Таким образом, ценностные типы не всегда хранятся в стеке. Более полезное утверждение: ссылочные типы никогда не сохраняются в стеке.

Так что не сосредотачивайтесь на стеке слишком muuch, это деталь реализации. Подробнее о значениях и ссылочных типах.

Ответ 5

Операция стека или операция кучи, они оба будут такими же, как вы, обращаетесь к адресу памяти, который находится в двух разных местах.

Типы значений маленькие, int, byte и т.д., они небольшие по размеру, и они очень часто ссылаются на математические вычисления. Поскольку они очень маленькие по размеру, от 4 до 16 байт макс (вы не должны использовать более 16 байт в типе значений для лучшей производительности), выделение такого небольшого пространства на кучу и освобождение, сборка мусора и т.д. Было бы очень дорогостоящим.

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

Стек может расти и сжиматься легко (не размер стека, а часть стека, используемого для текущего метода!), поскольку значения цен просто рассматриваются как смещенные от указателя стека, а их распределение и освобождение легко, так как его простое приращение и decrememnt на стековом указателе на общий размер всех используемых значений.

Где еще в ссылочном типе, каждый ссылочный объект имеет свое собственное распределение и размер, плюс CLR должен поддерживать таблицу объектов, которая как бы напоминает индекс фактических указателей в памяти, чтобы избежать переполнения буфера. Таким образом, один объект, который вы используете (ссылочный тип), фактически имеет два хранилища, одну запись индекса в справочной таблице CLR и фактическое пространство памяти. Вот почему его легко и быстро хранить типы значений в стеке.

Ответ 6

Для правильной работы программы важно, чтобы как объекты типа значения, так и объекты типа класса выказывали любые ссылки на них. Когда объект типа класса создается, создается ссылка, которая может быть свободно скопирована в любую область. Следовательно, вполне возможно, что ссылки на объект будут продолжать существовать даже после выхода текущего объема. Напротив, когда создается переменная типа значения, единственные ссылки, которые могут быть созданы, имеют тип короткого замыкания, который исчезнет до выхода текущей области. Тот факт, что никакая ссылка не может существовать для переменной value-type при выходе из текущей области, делает ее безопасной для хранения таких переменных в стеке.