Почему структуры хранятся на стеке, в то время как классы хранятся на "куче" (.NET)?

Что-то не так с библиотекой Pyrebase. Вот ссылка на проблему.

Решение состоит в том, чтобы добавить эти строки кода в ваше приложение.

# Temporarily replace quote function
def noquote(s):
    return s
pyrebase.pyrebase.quote = noquote

26
задан Fortyrunner 2 May 2009 в 20:57
поделиться

11 ответов

(отредактировано для освещения точек в комментариях)

Подчеркнуть: существуют различия и сходства между типами значений и ссылочными типами, но эти различия не имеют ничего для делать со стеком против кучи, и все, что связано с семантикой копирования против семантики ссылки. В частности, если мы сделаем:

Foo first = new Foo { Bar = 123 };
Foo second = first;

Тогда «первый» и «второй» говорят об одной и той же копии Foo ? или разные копии? Так уж сложилось, что стек является удобным и эффективным способом обработки типов значений как переменных. Но это деталь реализации.

(конец редактирования)

Re «целые типы значений идут в стек» ... - типы значений не всегда всегда идут в стеке;

  • если они являются полями в классе
  • , если они заключены в квадрат
  • , если они "
39
ответ дан 28 November 2019 в 06:33
поделиться

Марк Гравелл уже прекрасно объяснил разницу в том, как копируются значения и ссылочные типы, что является основным отличием между ними.

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

Когда вы создаете ссылочный тип, вы получаете ссылка на фактический объект, который существует в куче. Существует небольшой уровень косвенности, когда вы взаимодействуете с самим объектом. Эти ссылочные типы не могут быть созданы в стеке, потому что время жизни значений в стеке определяется, в значительной степени, по структуре вашего кода. Фрейм функции вызова метода будет вытолкнут из стека, когда функция вернется, например.

Однако, с типами значений, их семантика копирования позволяет компилятору, в зависимости от того, где он был создан, помещать его в стек , Если вы создадите локальную переменную, которая содержит экземпляр структуры в методе, а затем вернете ее, будет создана ее копия, как объяснил Марк выше. Это означает, что значение может быть безопасно помещено в стек, поскольку время жизни фактического экземпляра связано с функциональным фреймом метода. Каждый раз, когда вы отправляете его куда-то за пределы текущей функции, создается его копия, поэтому не имеет значения, если вы связываете существование исходного экземпляра с областью действия функции. Вдоль этих линий, Вы также можете понять, почему типы значений, которые захвачены замыканиями, должны помещаться в кучу: они переживают свою область видимости, потому что они также должны быть доступны из замыкания, которое можно свободно передавать.

Если бы это был ссылочный тип , тогда вы не будете возвращать копию объекта, а скорее ссылку, что означает, что фактическое значение должно храниться где-то еще, в противном случае, если вы вернули ссылку, а время жизни объекта было связано с областью, в которой он был созданный, он в конечном итоге будет указывать на пустое место в памяти.

Различие не в том, что «Типы значений идут в стек, ссылочные типы в куче». Суть в том, что обычно более эффективен доступ к объектам, находящимся в стеке, поэтому компилятор попытается поместить туда те значения, которые он может.

1
ответ дан 28 November 2019 в 06:33
поделиться

То, как компилятор и среда выполнения управляют управлением памятью, выросло за длительный период времени. Решение о выделении стековой памяти в сравнении с решением о выделении кучи памяти имело много общего с тем, что может быть известно во время компиляции и что может быть известно во время выполнения. Это было до того, как удалось запустить раз.

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

Современное управление памятью многое меняет. Среда выполнения .NET может контролировать эталонные типы и управляемую кучу с помощью сложных алгоритмов сбора мусора и управления памятью. Это также очень, очень глубокий предмет .

Я рекомендую вам ознакомиться с некоторыми текстами по компиляторам - я вырос на Aho, поэтому я рекомендую .

1
ответ дан 28 November 2019 в 06:33
поделиться

Типы значений помещаются в стек, а ссылочные типы - в кучу. Структура является типом значения.

Хотя в спецификации нет никаких гарантий по этому поводу, поэтому он может измениться в будущих выпусках:)

-2
ответ дан 28 November 2019 в 06:33
поделиться

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

Классы являются очень сложными и в основном очень большими типами по сравнению с типами значений, такими как структуры (или базовые типы - целые, символы и т. Д.). Поскольку выделение стека должно быть специализировано на эффективности выполнения программы, оно не служит оптимальным среда для хранения больших объектов.

Поэтому, чтобы удовлетворить оба ожидания, появилась эта отдельная архитектура.

7
ответ дан 28 November 2019 в 06:33
поделиться

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

Однако стоит отметить, что нет фундаментальной гарантии того, что все структуры будет помещен в стек. Эрик Липперт недавно написал интересную запись в блоге на эту тему.

10
ответ дан 28 November 2019 в 06:33
поделиться

Я считаю, что использование различий между стеком или кучей - это главное различие между ними. Возможно, эта статья проливает свет на ваш вопрос: Классы Csharp и структуры

]
0
ответ дан 28 November 2019 в 06:33
поделиться

Основное отличие состоит в том, что куча может содержать объекты, которые живут вечно, в то время как что-то в стеке является временным в том смысле, что оно исчезнет при выходе из вмещающего места вызова. Это потому, что когда кто-то входит в метод, он увеличивается для хранения локальных переменных, а также метода вызывающего. Когда метод выходит из (ab) обычно, например, return или из-за исключения, каждый кадр должен выталкиваться из стека. В конце концов интересующий кадр всплывает и все на нем теряется.

0
ответ дан 28 November 2019 в 06:33
поделиться

In some languages, like C++, objects are also value types.

To find an example for the opposite is harder, but under classic Pascal union structs could only be instantiated on the heap. (normal structs could be static)

In short: this situation is a choice, not a hard law. Since C# (and Java before it) lack procedural underpinnings, one can ask themselves why it needs structures at all.

The reason it is there, is probably a combination of needing it for external interfaces and to have a performant and tight complex (container-) type. One that is faster than class. And then it is better to make it a value type.

1
ответ дан 28 November 2019 в 06:33
поделиться

Это отличный вопрос; Я не освещал это в статье, на которую ссылался Марк Гравелл. Вот вторая часть:

http://blogs.msdn.com/ericlippert/archive/2009/05/04/the-stack-is-an-implementation-detail-part-two.aspx

9
ответ дан 28 November 2019 в 06:33
поделиться

Весь смысл использования стека в том, что он автоматически реализует и учитывает область видимости. Переменная, хранящаяся в стеке, существует до тех пор, пока функция, которая ее создала, не завершится и этот кадр стека функций не будет извлечен. Вещи, которые имеют локальную область видимости, естественны для хранилища стека, вещами, имеющими большую область действия, сложнее управлять в стеке. Объекты в куче могут иметь время жизни, которым можно управлять более сложным образом.

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

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

Стек и куча относятся к срокам службы, а семантика ссылки value v - почти побочный продукт.

Взгляните на Значение и ссылку

0
ответ дан 28 November 2019 в 06:33
поделиться