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


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

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

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

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

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

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

8 66

8 ответов:

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 указатель).

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

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

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

есть ли что-нибудь, что я пропустил?

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

"все типы значений будут выделены в стек" очень, очень неправильно; struct variables can жить в стеке, как переменные метода. Однако, поля на тип живу с этим типом. Если тип объявления поля является классом, значения находятся в куче как часть этого объекта. При объявлении типа поля структуры поля являются частью этой структуры где-либо эта структура живет.

даже переменные метода can быть в куче, если они плен (лямбда / Анон-метод), или часть (например) блока итератора.

простые меры

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

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

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

Так что в вашем случае

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

Я хотел бы предложить , вы можете начать читать блоги, написанные Эриком LIPPERTS.

блог Эрика

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

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

стек

The 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.

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

m-это ссылка на объект MyClass, поэтому m хранится в стеке основного потока, но объект MyClass хранится в куче. Поэтому myInt и myString хранятся в куче. Обратите внимание, что m является только ссылкой (адресом к памяти) и находится в основном стеке. когда m освобождается, GC очищает объект MyClass из кучи Более подробно читайте все четыре части этой статьи https://www.c-sharpcorner.com/article/C-Sharp-heaping-vs-stacking-in-net-part-i/