Почему C# (.Net) предпочитает стек для хранения типов значений? Какова основная причина этого дизайна? Это потому, что операции чтения/записи в стек лучше используют процессор машины?
Кроме того, может быть, вы можете обосновать, почему не другие?
Почему C# (.Net) предпочитает стек для хранения типов значений? Какова основная причина этого дизайна? Это потому, что операции чтения/записи в стек лучше используют процессор машины?
Кроме того, может быть, вы можете обосновать, почему не другие?
Эрик Липперт обсуждает этот здесь; во-первых, неверно, что типы значений хранятся в стеке. Они иногда бывают, но не так:
Когда они могут храниться в стеке, это удобный способ моделирования их жизненного цикла, но обязательно хранить их в стеке. Например, вы можете написать компилятор+CLI без имеющего стека.
C# ничего не хранит в стеке. C# — это язык программирования. Следовательно, более правильная версия вашего вопроса: почему компилятор Microsoft C# выдает инструкции CIL для выделения типов значений в стеке?
Ну, во-первых, это бывает только иногда. В стек не попадают:
Во-вторых, когда это возможно, это делается потому, что это эффективно. По сути, в модели памяти CLR освобождение памяти в стеке обходится очень дешево по сравнению с освобождением памяти в куче. С локальными типами значений вы можете быть уверены, что никто, кроме локальных, не будет ссылаться на память, поэтому вы можете избежать использования стека вместо кучи. Дополнительные сведения см. в разделе Эрик Липперт.
Наконец, что делает типы значений особенными, так это то, что они имеют семантику типов значений (копирование по значению), а не то, что они иногда размещаются в стеке. Спецификация C# не требует, чтобы компилятор выдавал инструкции для выделения типов значений в стеке. Спецификация C# требует, чтобы типы значений имели семантику типов значений.
Как указывает @Akash, это в основном связано с памятью. Во время разработки CLR было замечено (моя догадка основывалась на опыте работы с Java), что представление небольших примитивных типов в виде объектов с дескрипторами, подвергаемых сборщику мусора, приводит к большим затратам на отслеживание. Поэтому дизайнеры хотели получить «легкий» объект, за которым не нужно было следить.
В спецификации CLI нет особых требований к размещению примитивов в стеке; это артефакт реализации на машине. Важно то, что среда выполнения знает, где находятся экземпляры, благодаря построению четко определенных шаблонов памяти (называемых кадрами), а не индексу выделенных объектов GC. На машинах x86 (и подобных) это можно эффективно сделать с помощью стека.
Ваше утверждение не совсем верно. Улучшенная версия: C# хранит локальные переменные в стеке.
И в этом нет ничего особенного или нового, (почти) все языки программирования используют стек для локальных переменных и адресов возврата методов. Существует поддержка для этого вплоть до аппаратного обеспечения.
Кроме того, типы значений могут быть локальными переменными или полями внутри ссылочных типов. Таким образом, типы значений не всегда хранятся в стеке. Более полезное утверждение: ссылочные типы никогда не сохраняются в стеке.
Так что не зацикливайтесь на стеке слишком сильно, это деталь реализации. Узнайте о типах значений и ссылок.
Операция со стеком или операция с кучей, обе они будут одинаковыми, поскольку вы обращаетесь к адресу памяти, который находится в двух разных местах.
Типы значений small, int, byte и т. д., они небольшие по размеру, и на них очень часто ссылаются с точки зрения математических вычислений. Поскольку они очень малы по размеру, максимум от 4 до 16 байт (вы не должны использовать более 16 байт в типе значения для лучшей производительности), выделение такого небольшого пространства в куче и освобождение, сборка мусора и т. д. было бы очень дорогостоящим.
Для каждого метода, который мы вводим, в среднем мы определяем 10 локальных типов значений для внутреннего использования, что будет очень дорого для кучи в качестве ссылочных типов.
Стек может легко увеличиваться и уменьшаться (не размер стека, а часть стека, используемая для текущего метода !!), поскольку типы значений просто адресуются как смещение от указателя стека, а их выделение и освобождение легко, как его простое увеличение и уменьшение на указателе стека. по общему размеру всех используемых типов значений.
Где еще в ссылочном типе каждый ссылочный объект имеет свое собственное распределение и размер, плюс CLR должна поддерживать таблицу объектов, которая является своего рода индексом фактических указателей в памяти, чтобы избежать переполнения буфера. Таким образом, один объект, который вы используете (ссылочный тип), на самом деле имеет два хранилища, одну запись индекса в справочной таблице CLR и фактическое пространство памяти. Вот почему легко и быстро хранить типы значений в стеке.
Для правильной работы программы важно, чтобы сущности как типа значения, так и типа класса пережили любые ссылки на них. Когда создается объект типа класса, создается ссылка, которую можно свободно копировать в любую область. Следовательно, вполне возможно, что ссылки на объект будут продолжать существовать даже после выхода из текущей области. Напротив, когда создается переменная типа значения, могут быть созданы только ссылки краткосрочного типа, которые исчезнут до выхода из текущей области. Тот факт, что не может существовать ссылка на переменную типа значения при выходе из текущей области видимости, делает безопасным хранение таких переменных в стеке.