Во время работы программы данные должны помещаться в память. Объём памяти, занимаемый данными, и место их хранения определяются типом данных. При выполнении программы для хранения информации используются два участка памяти: Стек (Stack) и Куча (Heap).
Стек (Stack)
Стек — это непрерывный массив памяти, построенный по принципу последним пришёл — первым ушёл (LIFO). В нём хранятся три категории данных:
- Значения переменных отдельных типов
- Текущий контекст выполнения программы
- Параметры, передаваемые в методы

Операции с памятью стека управляются системой автоматически, разработчику не нужно выполнять ручные манипуляции. Понимание низкоуровневой логики стека упрощает анализ хода выполнения кода и изучение официальной документации C#.
Основные свойства стека
- Добавление и удаление данных возможно только на вершине стека
- Запись данных на вершину стека: операция Push (заталкивание)
- Извлечение данных с вершины стека: операция Pop (выталкивание)
Особенности памяти стека
- Очень высокая скорость выделения и освобождения памяти, используется непрерывный участок ОЗУ
- Время жизни привязано к вызову метода: после завершения работы метода фрейм стека уничтожается автоматически
- Хранится: значения переменных типов значений, параметры методов, локальные переменные, контекст выполнения

Чтобы лучше разобраться с принципом работы кучи, рассмотрим простой пример кода
class Program
{
static void Main(string[] args)
{
int a = 10;
int b = 20;
int sum = Add(a, b);
}
static int Add(int x, int y)
{
return x + y;
}
}
Code language: JavaScript (javascript)
Логика этого примера простая. С первой строки точки входа Main создаётся переменная целого числа a, на второй строке объявляется переменная b. Третья строка вызывает функцию Add, передавая значения a и b внутрь метода. Переменная x получает значение a, y — значение b, функция возвращает сумму x + y равную 30, результат передаётся обратно в точку вызова и записывается в sum. После завершения работы Add переменные x и y выталкиваются из стека, переменная sum принимает значение 30, после завершения Main программа закрывается. Далее мы разберём по шагам весь процесс заталкивания и выталкивания элементов стека.
Ход выполнения программы и последовательность операций Push/Pop для стека





После завершения Add x и y — локальные параметры этой функции, они последовательно выталкиваются, освобождая место в стеке для стабильной работы системы.
После выталкивания x и y исчезают, возвращённое значение 30 поступает в точку вызова для записи в sum.




Запомните важное правило: при выполнении функции переменные создаются сверху вниз и заталкиваются в стек последовательно a → b → вход в Add → x → y. После завершения Add x и y выталкиваются, затем заталкивается sum, при окончании Main переменные удаляются в обратном порядке: sum, b, a.
Куча (Heap)
Куча — большой участок памяти, предназначенный для динамического выделения блоков под объекты данных. В отличие от стека элементы кучи можно добавлять и удалять в любом порядке.
Программа не может вручную удалять объекты из кучи, очистку не ссылающихся недоступных объектов выполняет автоматически сборщик мусора GC среды CLR (Общеязыковая среда выполнения). Это избавляет разработчиков от ошибочных ручных операций освобождения памяти, характерных для других языков.
Кучу можно сравнить с большим письменным столом, на котором можно свободно размещать любые предметы. А стек, как мы выяснили ранее, похож на тубу для монет с единственным доступным концом.

Алгоритм работы сборщика мусора GC
- Программа создаёт три объекта в куче и хранит ссылки на них
- Программа перестаёт использовать один из объектов, все ссылки на него пропадают
- GC обнаруживает не ссылаемый объект и освобождает занимаемую им память
- Сбор завершён, освобождённый участок памяти выделяется под новые объекты
Особенности памяти кучи
- Память не непрерывная, скорость выделения ниже, чем у стека
- Время жизни не привязано к границам метода, управляется централизованно сборщиком GC
- Хранится: экземпляры ссылочных типов (классы, массивы, делегаты и т.д.); в стеке сохраняются только адреса памяти объектов из кучи
Рассмотрим ещё один наглядный пример. Как сказано выше, локальные переменные базовых типов хранятся в стеке, а пользовательские типы обычно размещаются в куче. Ознакомьтесь с кодом ниже:
class Program
{
static void Main(string[] args)
{
int a = 10;
int b = 20;
Student tom = new Student("Tom", 12);
Student lucy = new Student("Lucy", 12);
}
}
class Student
{
//Поля класса
private string name;
private int age;
//Конструктор, разберём позже
public Student(string name, int age)
{
this.name = name;
this.age = age;
}
//Метод класса
public void DisplayInfo()
{
Console.WriteLine($"Name: {name}, Age: {age}");
}
}
Code language: JavaScript (javascript)
На схеме ниже показано расположение в памяти четырёх переменных Main: a, b, tom, lucy. Как и при разборе стека, код выполняется сверху вниз: сначала заталкивается a, затем b, значения этих переменных хранятся напрямую в стеке.


Например, данные tom лежат в блоке кучи 00001, в стеке сохраняется адрес 00001 для последующего поиска данных.
После завершения работы Main ссылка lucy: 01010 выталкивается из стека и уничтожается, но удаляется только адрес, а не сами данные объекта в куче. В этот момент объект кучи теряет все ссылки из переменных стека.


Участки памяти
Стек и куча — логические разделы памяти на уровне программного обеспечения, не физическое разделение оборудования.
Стек и куча являются лишь программным логическим разбиением памяти, физическая ОЗУ не имеет отдельных аппаратных блоков с пометкой «зона стека» или «зона кучи».
Физическая оперативная память RAM состоит из единых микросхем с последовательными физическими адресами, никаких маркеров разделения стека и кучи в аппаратуре нет
Операционная система выделяет каждому запущенному процессу отдельное виртуальное адресное пространство, которое предварительно делит на четыре основные логические сегмента:
Сегмент кода: хранит скомпилированные инструкции программы
Глобальный статический сегмент: статические переменные, константы
Сегмент стека: основной и дочерние потоки программы имеют каждый собственный независимый участок стека
Сегмент кучи: большой общий пул памяти для динамического выделения
Стек и куча, о которых идёт речь — это лишь логические области, выделенные ОС для каждого процесса, аппаратной изоляции между ними не существует.
Стек против Кучи