Ответ
Память для переменных внутри горутины может аллоцироваться как на её стеке, так и в общей куче (heap). Место аллокации определяется компилятором на этапе анализа побега (escape analysis).
Стек горутины:
- Каждая горутина при запуске получает собственный небольшой стек (обычно 2 КБ).
- Этот стек может динамически расти и сжиматься по мере необходимости, что делает создание горутин очень "дешёвым".
- Переменные, которые не "сбегают" (т.е. используются только в рамках одной функции и не передаются по ссылке наружу), размещаются на стеке. Это очень быстро и не создает нагрузки на сборщик мусора (GC).
Анализ побега (Escape Analysis):
- Это процесс, в ходе которого компилятор определяет, будет ли переменная доступна после завершения функции, в которой она была создана.
- Если на переменную остаются ссылки за пределами её стекового фрейма (например, возвращается указатель на неё), переменная "сбегает" в кучу.
Куча (Heap):
- Переменные, которые "сбежали", аллоцируются в общей для всех горутин куче.
- Память в куче управляется сборщиком мусора (GC), который отслеживает и освобождает неиспользуемые объекты.
Пример "побега" в кучу:
// x будет аллоцирован в куче, так как ссылка на него
// возвращается из функции и переживёт её стековый фрейм.
func foo() *int {
x := 42
return &x
}
Ключевая идея: Go стремится размещать данные на стеке для максимальной производительности и только при необходимости перемещает их в кучу, где за их жизненным циклом следит GC.