Типы ссылок живут в куче, типы значений живут в стеке

при чтении "С# in Depth" я проходил раздел "Типы ссылок, которые живут в куче, типы значений живут в стеке".

Теперь я понял (в основном для типа ref):

class Program
{
    int a = 5;  // stored in heap

    public void Add(int x, int y) // x,y stored in stack
    {
        int c = x + y;  // c  stored in stack
    }
}

Просто хочу уточнить, правильны ли мои предположения. Благодарю. РЕДАКТИРОВАТЬ: Я должен был использовать переменные diff, я думаю, что создал confusion.so я изменил код.

EDIT: Да, как сказал Джон, это миф, я должен был упомянуть об этом. Мои извинения.

Ответ 2

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

Есть не менее шести мест, где значение типа значения может жить с мнимыми (x86 и x64) дрожаниями:

  • в кадре стека, помещенном там локальным объявлением переменной или вызовом метода
  • в регистре CPU - очень распространенная оптимизация, выполняемая JIT в сборке Release. И используется для передачи аргументов в метод, первые два x86, четыре для x64. И локальные переменные, если возможно
  • в стеке FPU, используемом джиттером x86 для значений с плавающей запятой
  • в куче GC, когда значение является частью ссылочного типа
  • в куче загрузчика AppDomain, когда переменная объявлена ​​static
  • в потоковом локальном хранилище, когда переменная имеет атрибут [ThreadStatic].

Объекты ссылочного типа обычно выделяются в куче GC. Но я знаю об одном конкретном исключении, интернированные строки, созданные из литералов в исходном коде, выделяются в куче загрузчика AppDomain. Это полностью ведет себя как объект во время выполнения, за исключением того, что он не связан с кучей GC, сборщик просто не видит его.

Адресация фрагмента кода:

  • да, "a", вероятно, будет храниться в куче GG
  • "x" всегда передается в регистре CPU на x86 и x64. "y" будет в регистре CPU на x64, стек на x86.
  • "c", вероятно, вообще не существует, удаляется компилятором JIT, потому что код не имеет эффекта.

Ответ 3

c остается в стеке, потому что по меньшей мере это тип значения в то время как a в управляемой куче из-за того, что это поле ссылочного типа

Ответ 4

Места хранения (переменные, поля, элементы массива и т.д.) Ссылочных типов содержат ссылки на объекты в куче; места хранения примитивных типов значений хранят свои значения внутри себя; хранилища структурных типов содержат в себе все свои поля, каждое из которых может быть ссылкой или типом значения. Если экземпляр класса содержит две разные ненулевые строки, Point и целое число, координаты X и Y точки, а также отдельное целое число и ссылки на две строки будут храниться в одной куче. объект. Каждая из строк будет храниться в отдельном объекте кучи. Ключевой момент в отношении мест хранения классов и структур состоит в том, что за исключением случая, когда сущность класса содержит ссылку на себя, каждое поле ненулевого ссылочного типа в классе или структуре будет содержать ссылку на какой-то другой объект, который будет быть в куче.

Ответ 5

Подумайте об этом в терминах C/C++.

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

Другими словами,> объект & lt; на который указывает ссылочный тип, находится в куче, это просто сам указатель в стеке. Утечки памяти происходят, когда программа выталкивает указатель из стека, но память в куче не была освобождена для use--. Как узнать, какую память освободить, если ссылка на ее местоположение была потеряна? Что ж, C/C++ не смог, вы должны были сделать это самостоятельно, прежде чем ссылка была выкинута из стека и потеряна навсегда, но именно там, где появляются современные языки со своей причудливой манерой "кучи мусора". По-прежнему предпочтительнее явно очистить любую выделенную кучу памяти, чем неявно, оставив ее для захвата GC, это "дешевле" таким образом (с точки зрения ресурсов ЦП).

Ответ 6

Цитирую Джона Скита из его известного блога о том, как и где типы ссылок и значений хранятся в приложении .Net:

Слот памяти для переменной хранится либо в стеке, либо в куча. Это зависит от контекста, в котором он объявлен:

  1. Каждая локальная переменная (т.е. объявленная в методе) хранится в стеке. Это включает в себя переменные ссылочного типа - сама переменная в стеке, но помните, что значение переменной ссылочного типа это только ссылка (или ноль), а не сам объект. метод параметры также считаются локальными переменными, но если они объявлены с модификатор ref, они не получают свой собственный слот, а делят его с переменная, используемая в вызывающем коде. Смотрите мою статью о параметре прохождение для более подробной информации.
  2. Переменные экземпляра для ссылочного типа всегда находятся в куче. Это где сам объект "живет".
  3. Переменные экземпляра для типа значения хранятся в том же контексте, что и переменная, которая объявляет тип значения. Слот памяти для Экземпляр эффективно содержит слоты для каждого поля в пределах экземпляр. Это означает (учитывая два предыдущих пункта), что структура переменная, объявленная в методе, всегда будет в стеке, тогда как переменная структуры, которая является полем экземпляра класса, будет на куча.
  4. Каждая статическая переменная хранится в куче, независимо от того, объявлена ли она в ссылочном типе или типе значения. Есть только Всего один слот, независимо от того, сколько экземпляров создано. (Там не должно быть никаких экземпляров, созданных для существования одного слота хотя.) Детали того, на какой именно куче находятся переменные, сложный, но подробно объясненный в статье MSDN о тема.