Что такое куча (heap) в Go и как она используется?

Ответ

Куча (heap) — это область в оперативной памяти, где Go хранит динамически выделяемые объекты. В отличие от стека, память в куче управляется не компилятором, а сборщиком мусора (Garbage Collector, GC).

Куча vs. Стек

ХарактеристикаСтек (Stack)Куча (Heap)
СкоростьОчень быстрый доступ (LIFO)Более медленный доступ
НазначениеЛокальные переменные, вызовы функцийОбъекты, переживающие вызов функции, разделяемые данные
УправлениеАвтоматическое (компилятор)Автоматическое (сборщик мусора)
РазмерФиксированный и небольшойДинамический и большой

Escape Analysis (Анализ "убегания")

Компилятор Go решает, где выделить переменную — в стеке или в куче. Этот процесс называется escape analysis. Переменная "убегает" в кучу, если:

  • На нее возвращается указатель из функции.
  • Она отправляется в канал или используется в другой горутине.
  • Ее размер неизвестен на этапе компиляции (например, слайс, размер которого определяется в рантайме).

Пример:

// Эта функция заставит 's' "убежать" в кучу,
// так как указатель на слайс возвращается наружу.
func createSlice() *[]int {
    s := make([]int, 1000) // s выделяется в куче
    return &s
}

// В этой функции 's' останется в стеке,
// так как используется только локально.
func createLocalSlice() {
    s := make([]int, 10) // s, скорее всего, будет выделен в стеке
    s[0] = 1
}

Влияние на производительность

Частое выделение памяти в куче создает нагрузку на сборщик мусора (GC). Работа GC может приводить к коротким остановкам программы (stop-the-world), что критично для высокопроизводительных приложений. Поэтому хорошей практикой в Go является минимизация аллокаций в куче, где это возможно.

Проанализировать "убегание" можно с помощью флага компилятора:
go build -gcflags="-m" ./...