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

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

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

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

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

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

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

Ответ 1

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

Ответ 2

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

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

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

Есть ли что-то, что я пропустил?

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

Ответ 3

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

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

Ответ 4

Отличное объяснение:

Ответ 5

простые меры

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

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

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

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

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

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

Блог Эрика

Ответ 6

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

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