Что в Go хранится в стеке, а что — в куче? (Stack vs Heap)

Ответ

В Go компилятор сам решает, где размещать переменные, с помощью анализа逃逸 (escape analysis). Основной принцип: если переменная может быть использована после завершения функции, она "сбегает" в кучу. В противном случае она остается в стеке.

Стек (Stack)

Это область памяти, работающая по принципу LIFO (Last-In, First-Out). Память выделяется и освобождается очень быстро — простым сдвигом указателя стека.

Что обычно хранится в стеке:

  • Локальные переменные простых типов (int, bool, структуры без указателей), чей жизненный цикл ограничен вызовом функции.
  • Аргументы, передаваемые в функцию.
  • Адреса возврата из функций.

Преимущества:

  • Скорость: Очень быстрое выделение и освобождение памяти.
  • Автоматическое управление: Память автоматически очищается при выходе из функции, не нагружая сборщик мусора (GC).

Куча (Heap)

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

Что хранится в куче (куда "сбегают" переменные):

  • Переменные, на которые есть ссылки за пределами функции (например, если функция возвращает указатель на локальную переменную).
  • Данные, захваченные замыканиями (closures), которые переживают функцию.
  • Слайсы или мапы, которые растут и требуют переаллокации памяти.
  • Данные, отправляемые в каналы (так как их может получить другая горутина в любое время).

Особенности:

  • Управление: Память в куче управляется сборщиком мусора (GC), что добавляет накладные расходы.
  • Скорость: Выделение памяти медленнее, чем в стеке.

Пример Escape Analysis

// b не сбегает и будет размещена в стеке
func createOnStack() int {
    b := 10
    return b
}

// p сбегает в кучу, так как на неё будет ссылка
// вне функции
func createOnHeap() *int {
    p := new(int)
    *p = 42
    return p // p "сбегает" в кучу
}

Чтобы проверить, сбегает ли переменная, можно использовать флаг компилятора: go build -gcflags='-m' .