Перейти к содержанию
Innovialabs

Стек и куча: что нужно знать каждому разработчику

Основы3 мин

Коротко

Стек — быстрая память для локальных данных функции, которая освобождается сама при выходе из неё; куча — гибкая память для данных с произвольным временем жизни, но выделение в ней дороже.

Коротко: в чём разница

У программы есть две основные области памяти для данных:

  • Стек (stack) — хранит локальные переменные и служебную информацию вызова функции. Выделение и освобождение почти бесплатны: при входе в функцию создаётся кадр (frame), при выходе он исчезает целиком.
  • Куча (heap) — хранит данные, которые должны жить дольше вызова функции или чей размер известен только во время работы. Память здесь выделяется явно (new, malloc) или неявно, а освобождается вручную, сборщиком мусора или по правилам владения.
СтекКуча
Время жизниПока выполняется функцияПока данные нужны
Скорость выделенияОчень высокаяНиже
РазмерОграничен, задаётся ОС и настройкамиНамного больше
Кто освобождаетАвтоматически при выходеGC, программист или владелец
ДоступОдин поток — свой стекОбщая для всех потоков

Как работает стек

Стек работает по принципу LIFO — последним пришёл, первым ушёл. Когда функция a вызывает b, кадр b кладётся поверх кадра a. Когда b возвращается, её кадр снимается, и все её локальные переменные пропадают.

Поэтому нельзя возвращать указатель на локальную переменную в C: после выхода из функции эта память уже чужая.

Как работает куча

Куча — большой пул памяти, из которого аллокатор выдаёт блоки нужного размера. Это гибко, но цена такая:

  • аллокатору нужно найти свободный блок;
  • память может фрагментироваться;
  • в языках с GC каждая аллокация — будущая работа для сборщика;
  • объекты разбросаны по памяти, что хуже для кэша процессора.

Значимые и ссылочные типы

Популярное упрощение «значимые типы на стеке, ссылочные в куче» неточно. Точнее так: значимый тип хранит сами данные, ссылочный — адрес данных в куче. Где окажется значение, зависит от того, где оно объявлено.

  • Java: примитивы (int, double) — значения; объекты — в куче, переменная хранит ссылку. JIT может избежать выделения в куче через escape analysis.
  • C#: struct — значимый тип, class — ссылочный. Но struct внутри поля класса живёт в куче вместе с объектом.
  • Go: компилятор сам решает, где разместить значение, через escape analysis. Если значение «убегает» из функции (например, на него возвращается указатель), оно уходит в кучу.
  • Python и JavaScript: почти всё — объекты в куче, детали размещения скрыты движком.

Практическое следствие — разная семантика копирования:

struct PointS { public int X; }
class  PointC { public int X; }

var a = new PointS { X = 1 }; var b = a; b.X = 2; // a.X == 1, скопировано значение
var c = new PointC { X = 1 }; var d = c; d.X = 2; // c.X == 2, скопирована ссылка

В Go можно посмотреть решения компилятора:

go build -gcflags=-m ./...

Stack overflow

Стек ограничен, поэтому слишком глубокая рекурсия или огромные локальные массивы его переполняют. Выглядит это по-разному:

  • Java — StackOverflowError;
  • JavaScript — RangeError: Maximum call stack size exceeded;
  • Python — RecursionError (интерпретатор ограничивает глубину заранее);
  • C/C++ — обычно аварийное завершение процесса.

Как лечить: переписать рекурсию в цикл, использовать явную структуру данных (свой стек в куче), не хранить большие массивы в локальных переменных.

Почему это важно для производительности

  • Меньше аллокаций в куче — меньше работы для GC и короче паузы.
  • Переиспользуйте буферы в горячих циклах вместо создания новых объектов на каждой итерации.
  • Компактные данные быстрее: массив значений обходится эффективнее, чем массив ссылок на разбросанные объекты.
  • Не оптимизируйте вслепую. Сначала профилировщик, потом изменения.

Частые вопросы

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

Поможем с этим

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

Обсудить проект

Читайте также

Есть идея или задача? Расскажите нам

Ответим в течение рабочего дня и предложим решение. Консультация бесплатная.