Выделение распределения кучи и стека (.NET)

Из SO ответ 1 о куче и стеке, он поднял мне вопрос: почему это важно знать, где выделяются переменные?

В другом ответе кто-то указал, что стек быстрее. Это единственное следствие? Может ли кто-нибудь привести пример кода, где простое изменение местоположения места могло бы решить проблему (например, производительность)?

Обратите внимание, что этот вопрос специфичен для .NET

1 вопрос удаляется из SO.

Ответ 1

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

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

Подобным образом компилятор С# может решить выделить все локальные переменные в куче - в стек будет только ссылка на экземпляр MyMethodLocalVariables, и через него будет реализован весь доступ к переменной. (Фактически, переменные, захваченные делегатами или итераторами, уже имеют такое поведение.)

Ваш вопрос возник, пока Эрик Липперт просматривал С# в Depth - у меня есть раздел, объясняющий, что происходит там, где находится С# 1, и он считал, что разработчики shouldn ' t уход.

Ответ 2

(edit:). В моем первоначальном ответе содержались упрощенные "структуры, выделенные в стеке", а путанные значения "стоп-vs-heap" и "value-vs-reference" относятся к бит, потому что они связаны в С#.)

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

public class Foo
{
   public int X = 0;
}

Теперь рассмотрим следующий код:

Foo foo = new Foo();
Foo foo2 = foo;
foo2.X = 1;

В этом примере foo и foo2 являются ссылками на один и тот же объект. Установка X на foo2 также повлияет на foo1. Если мы изменим класс Foo на структуру, это уже не так.. Это связано с тем, что структуры не доступны через ссылки. Присвоение foo2 действительно сделает копию.

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

Ответ 3

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

Ответ 4

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

Типы ссылок всегда выделяются в куче. Типы значений по умолчанию распределяются по стеку. Исключением является то, что тип значения является частью ссылочного типа, и в этом случае он распределяется по куче вместе со ссылочным типом. То есть конструктор типа принимает это решение от имени пользователей.

В таких языках, как C или С++, пользователь может решить, где распределяются данные, и для некоторых особых случаев он может быть значительно быстрее выделять из стека по сравнению с распределением из кучи.

Это связано с тем, как распределяются кучи для C/С++. Фактически распределение кучи довольно быстро в .NET(за исключением случаев, когда он вызывает сбор мусора), поэтому, даже если вы можете решить, где распределить, я предполагаю, что разница не будет существенной.

Однако, поскольку куча - сбор мусора, а стек - нет, очевидно, вы увидите некоторые различия в некоторых случаях, но это вряд ли актуально, учитывая тот факт, что у вас на самом деле нет выбора в .NET.

Ответ 5

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