Ответ
Escape-анализ (escape analysis) — это процесс, который компилятор Go выполняет во время компиляции, чтобы определить, где хранить переменную: в стеке (stack) или в куче (heap).
Основная идея:
Размещение переменных в стеке намного производительнее, так как память выделяется и освобождается простым смещением указателя стека. Память в куче требует более сложных механизмов выделения и сборки мусора, что создает дополнительную нагрузку.
Компилятор анализирует, может ли переменная "сбежать" (escape) из области видимости функции. Если на переменную останутся ссылки после завершения функции, она должна быть размещена в куче. В противном случае она безопасно размещается в стеке.
Когда происходит "побег" в кучу?
- Возврат указателя: Когда функция возвращает указатель на локальную переменную.
- Отправка в канал: Отправка указателя на локальную переменную в канал (если получатель может пережить функцию).
- Сохранение в срезе: Сохранение указателя в срезе, который может быть доступен вне функции.
- Неизвестный размер: Когда размер переменной неизвестен на этапе компиляции (например, при создании среза, размер которого определяется динамически).
Пример:
// x "сбегает" в кучу, так как на него будет ссылка вне функции foo
func foo() *int {
x := 42
return &x
}
// y остается в стеке, так как возвращается копия значения
func bar() int {
y := 10
return y
}
Как это проверить?
Чтобы увидеть решения компилятора, можно использовать флаг -gcflags="-m"
при сборке:
go build -gcflags="-m" main.go
Это покажет, какие переменные были перемещены в кучу (escapes to heap
).