c# - стеке - Распределение памяти: стек против кучи?




стек куча очередь (6)

стек

stack представляет собой блок памяти для хранения local variables и parameters . Стек логически растет и сжимается по мере ввода и выхода функции.

Рассмотрим следующий метод:

public static int Factorial (int x)
{
    if (x == 0) 
    {
        return 1;
    }

    return x * Factorial (x - 1);
}

Этот метод является рекурсивным, что означает, что он называет себя. Каждый раз, когда вводится метод, в стеке выделяется новый int , и каждый раз, когда метод завершается, int освобождается .

отвал

  • Куча - это блок памяти, в котором находятся objects (например, reference-type instances ). Всякий раз, когда создается новый объект, он выделяется в куче, и возвращается ссылка на этот объект. Во время выполнения программы куча начинает заполняться по мере создания новых объектов. В среде выполнения есть сборщик мусора, который периодически освобождает объекты из кучи, поэтому ваша программа не запускает Out Of Memory . Объект имеет право на освобождение, как только на него не ссылаются все, что само по себе alive .
  • Куча также сохраняет static fields . В отличие от объектов, выделенных на кучу (которые могут собирать мусор), these live until the application domain is torn down .

Рассмотрим следующий метод:

using System;
using System.Text;

class Test
{
    public static void Main()
    {
        StringBuilder ref1 = new StringBuilder ("object1");
        Console.WriteLine (ref1);
        // The StringBuilder referenced by ref1 is now eligible for GC.

        StringBuilder ref2 = new StringBuilder ("object2");
        StringBuilder ref3 = ref2;
        // The StringBuilder referenced by ref2 is NOT yet eligible for GC.
        Console.WriteLine (ref3); // object2
    }
}    

В приведенном выше примере мы начинаем с создания объекта StringBuilder, на который ссылается переменная ref1, а затем выписываем его содержимое. Этот объект StringBuilder сразу же получает право на сбор мусора, потому что ничто впоследствии не использует его. Затем мы создаем другой StringBuilder, на который ссылается переменная ref2, и копируем эту ссылку на ref3. Несмотря на то, что ref2 не используется после этой точки, ref3 сохраняет один и тот же объект StringBuilder живым, гарантируя, что он не станет пригодным для сбора до тех пор, пока мы не закончим использование ref3.

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

https://code.i-harness.com

Я путаюсь с основами распределения памяти между Stack vs Heap . В соответствии с стандартным определением (все, что все говорят) все типы значений будут распределены по стекам, а ссылочные типы войдут в кучу .

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

class MyClass
{
    int myInt = 0;    
    string myString = "Something";
}

class Program
{
    static void Main(string[] args)
    {
       MyClass m = new MyClass();
    }
}

Теперь, как распределение памяти произойдет в c #? Будет ли объект MyClass (т. MyClass m ) полностью выделен куче? То есть, int myInt и string myString будут идти в кучу?

Или объект будет разделен на две части и будет выделен обоим местам памяти, которые представляют собой стек и кучу?


«Все типы VALUE будут выделены для Stack» очень, очень неправильно; переменные структуры могут жить в стеке, как переменные метода. Тем не менее поля с типом живут с этим типом . Если тип объявления поля является классом, значения находятся в куче как часть этого объекта. Если тип объявления поля является структурой, поля являются частью этой структуры, где бы она ни существовала .

Даже переменные метода могут находиться в куче, если они захвачены (метод лямбда / anon) или часть (например) блока итератора.


Вы должны рассмотреть вопрос о том, где объекты будут выделены в качестве детали реализации. Для вас не имеет значения, где хранятся биты объекта. Может возникнуть вопрос, является ли объект ссылочным типом или типом значения, но вам не нужно беспокоиться о том, где он будет храниться, пока вы не начнете оптимизировать поведение сбора мусора.

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

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

Я что-то пропустил?

Конечно, я был бы упущен, если бы не ссылку на сообщения Эрика Липперта по теме:


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

Эта ссылка также полезна http://www.programmerinterview.com/index.php/data-structures/difference-between-stack-and-heap/


простые меры

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

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

Типы ссылок передаются по ссылке (агаи не считают ссылку будет хранить адрес снова в некоторых будущих версиях, он может храниться в некоторых других структурах данных).

поэтому в вашем случае

myInt - это int, который инициализируется в классе, который ссылается на ссылочный тип, поэтому он будет привязан к экземпляру класса, который будет храниться в «HEAP».

я бы предложил, вы можете начать читать блоги, написанные ERIC LIPPERTS.

Блог пользователя Eric


m выделяется в куче, и включает myInt . Ситуации, когда примитивные типы (и структуры) выделяются в стеке, - это вызов метода, который выделяет место для локальных переменных в стеке (потому что он быстрее). Например:

class MyClass
{
    int myInt = 0;

    string myString = "Something";

    void Foo(int x, int y) {
       int rv = x + y + myInt;
       myInt = 2^rv;
    }
}

rv , x , y все будут в стеке. myInt находится где-то в куче (и должен быть доступ через this указатель).







heap