Память в Go: как работает escape analysis и куда уходят переменные
Разбираем стек и кучу в Go на примерах: почему одни переменные живут только внутри функции, а другие убегают в кучу.
Go — язык, который часто называют простым и быстрым. Но под капотом он делает кучу магии, особенно когда речь идёт о работе с памятью. Понимание того, где и как хранятся данные, может помочь писать более эффективный код, избегать лишних аллокаций и лучше понимать поведение программы.
Стек и куча: основы
Стек (stack) — память, которая работает по принципу LIFO (last in, first out). Переменные живут до выхода из функции. Работа со стеком быстрая и почти бесплатная.
Куча (heap) — область памяти для объектов, чьё время жизни нельзя заранее определить. Управляется сборщиком мусора (GC). Аллокации дороже, а сборка может замедлять программу.
Главное отличие: на стеке память освобождается автоматически при выходе из функции, а в куче за этим следит GC.

Escape analysis: кто сбежал в кучу?
Когда компилятор Go встречает переменную, он решает, где её хранить — в стеке или куче. Этот процесс называется escape analysis.
Если переменная "сбегает" за пределы функции, она отправляется в кучу. Если нет — остаётся в стеке.
Пример 1. Локальная переменная (остаётся в стеке)
func sum(a, b int) int {
c := a + b
return c
}
Пример 2. Переменная уходит в кучу
func makePointer() *int {
x := 42
return &x
}
Здесь x
возвращается по указателю. После выхода из функции стек очистится, и значение потерялось бы. Поэтому x
"сбегает" в кучу, чтобы продолжить жить.

Проверяем escape analysis
go build -gcflags="-m" main.go
Пример вывода:
./main.go:5:6: moved to heap: x
Когда переменные убегают в кучу?
Возвращаются из функции по указателю.
Сохраняются в замыкании.
Передаются в интерфейс (иногда).
Размер структуры слишком большой, чтобы поместиться в стек.
Пример 3. Замыкание
func adder() func(int) int {
sum := 0
return func(x int) int {
sum += x
return sum
}
}
Здесь sum
хранится в куче, потому что нужно, чтобы она жила дольше функции adder
.
Стек vs куча на практике
Характеристика | Стек | Куча |
---|---|---|
Время жизни | Пока выполняется функция | До сборки GC |
Скорость доступа | Очень быстрая | Медленнее |
Управление | Автоматическое | Сборщик мусора |
Где хранятся | Локальные переменные | Указатели, замыкания, долгоживущие объекты |
Как писать эффективный код
Избегайте лишних указателей. Чем больше указателей, тем выше шанс уйти в кучу.
По возможности используйте значения, а не ссылки.
Следите за escape analysis. Иногда Go аллоцирует память в куче, хотя кажется, что это не нужно.
Не бойтесь кучи слишком сильно. Оптимизация важна, но преждевременная оптимизация — зло.
Итог
Понимание того, где хранятся данные в Go, позволяет писать более производительный код. Escape analysis — это инструмент, который решает судьбу каждой переменной. А зная его правила, можно избежать неожиданных тормозов из-за лишних аллокаций в куче.
В Кодике есть полноценный курс по Go — от самых основ до продвинутых тем. Мы разбираем синтаксис, работу с памятью, конкурентность и пишем мини-проекты, которые помогут закрепить знания.
А ещё у нас есть активный telegram-канал, где мы обсуждаем крутые идеи, делимся опытом и вместе разбираем задачи — учиться становится не только полезно, но и весело.