Ответ
В 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, так как данные в куче
}
Слайсы, мапы и каналы всегда выделяют базовую структуру данных в куче.