Подтвердить что ты не робот

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

Я знаю, что одно из различий между классами и структурами состоит в том, что экземпляры структуры хранятся в стеке, а экземпляры классов (объекты) хранятся в куче.

Так как классы и структуры очень похожи. Кто-нибудь знает разницу в этом конкретном различии?

4b9b3361

Ответ 1

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

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

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

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

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

Re все "значения типа идут в стек" вещь... - типы значений не всегда идут в стек;

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

то они идут в кучу (последние два фактически являются просто экзотическими примерами первого)

то есть.

class Foo {
    int i; // on the heap
}

static void Foo() {
    int i = 0; // on the heap due to capture
    // ...
    Action act = delegate {Console.WriteLine(i);};
}

static IEnumerable<int> Foo() {
    int i = 0; // on the heap to do iterator block
    //
    yield return i;
}

Кроме того, Эрик Липперт (как уже отмечалось) имеет отличную запись в блоге по этому вопросу

Ответ 2

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

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

Ответ 4

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

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

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

Ответ 5

В некоторых языках, таких как С++, объекты также являются типами значений.

Найти пример противоположности сложнее, но в классическом объединении Pascal структуры могут быть созданы только в куче. (нормальные структуры могут быть статическими)

Короче: эта ситуация - это выбор, а не жесткий закон. Поскольку С# (и Java перед ним) не имеют процедурных оснований, можно спросить себя, зачем им вообще нужны структуры.

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

Ответ 6

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

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

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

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

Ответ 7

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

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

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

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

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

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

Ответ 8

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

Ответ 9

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

Ответ 10

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

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

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

Стек и куча - это времена жизни, а семантика значений v - почти по продукту.

Посмотрите Значение и ссылка

Ответ 11

Типы значений идут в стек, ссылочные типы переходят в кучу. Структура - это тип значения.

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