Что такое куча (heap) в Go и чем она отличается от стека (stack)?

Ответ

В Go, как и во многих других языках, память для переменных выделяется либо в стеке (stack), либо в куче (heap).

Куча (Heap) — это область памяти для динамического выделения. Переменные, размещенные в куче, не привязаны к времени жизни одной функции и управляются сборщиком мусора (GC).

Ключевые отличия от стека:

  • Время жизни:

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

    • Стек: Очень быстрое выделение и освобождение.
    • Куча: Более медленное выделение из-за необходимости поиска свободного блока памяти и дополнительной нагрузки на GC.
  • Решение о размещении: В Go компилятор решает, где разместить переменную, с помощью анализа побега (escape analysis). Если компилятор доказывает, что переменная не используется за пределами функции, она размещается в стеке. В противном случае она "сбегает" в кучу.

Пример "побега" в кучу:

// Эта функция возвращает указатель на переменную, созданную внутри нее.
// Переменная 'x' не может быть размещена в стеке, так как стек будет очищен после выхода из функции.
// Поэтому 'x' "сбегает" в кучу.
func createPointer() *int {
    x := 10
    return &x // &x сбегает в кучу
}

func main() {
    ptr := createPointer()
    fmt.Println(*ptr) // Успешно выведет 10, так как данные в куче
}

Слайсы, мапы и каналы всегда выделяют базовую структуру данных в куче.