Как в Go управляется память, выделяемая для горутин?

Ответ

Память для переменных внутри горутины может аллоцироваться как на её стеке, так и в общей куче (heap). Место аллокации определяется компилятором на этапе анализа побега (escape analysis).

  1. Стек горутины:

    • Каждая горутина при запуске получает собственный небольшой стек (обычно 2 КБ).
    • Этот стек может динамически расти и сжиматься по мере необходимости, что делает создание горутин очень "дешёвым".
    • Переменные, которые не "сбегают" (т.е. используются только в рамках одной функции и не передаются по ссылке наружу), размещаются на стеке. Это очень быстро и не создает нагрузки на сборщик мусора (GC).
  2. Анализ побега (Escape Analysis):

    • Это процесс, в ходе которого компилятор определяет, будет ли переменная доступна после завершения функции, в которой она была создана.
    • Если на переменную остаются ссылки за пределами её стекового фрейма (например, возвращается указатель на неё), переменная "сбегает" в кучу.
  3. Куча (Heap):

    • Переменные, которые "сбежали", аллоцируются в общей для всех горутин куче.
    • Память в куче управляется сборщиком мусора (GC), который отслеживает и освобождает неиспользуемые объекты.

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

// x будет аллоцирован в куче, так как ссылка на него
// возвращается из функции и переживёт её стековый фрейм.
func foo() *int {
    x := 42
    return &x
}

Ключевая идея: Go стремится размещать данные на стеке для максимальной производительности и только при необходимости перемещает их в кучу, где за их жизненным циклом следит GC.