Почему типы значений хранятся в стеках? - PullRequest
11 голосов
/ 19 декабря 2009

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

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

Ответы [ 6 ]

30 голосов
/ 19 декабря 2009

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

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

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

13 голосов
/ 19 декабря 2009

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

Ну, во-первых, иногда. Следующие не идут в стек:

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

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

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

4 голосов
/ 19 декабря 2009

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

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

2 голосов
/ 19 декабря 2009

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

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

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

0 голосов
/ 29 августа 2011

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

0 голосов
/ 19 декабря 2009

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

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

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

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

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

...