Где и как горутины управляют памятью? (Стек и куча)

Ответ

Память для горутины можно разделить на две категории: собственный стек горутины и данные, которые горутина аллоцирует в процессе работы.

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

  • Аллоцируется в куче (heap). В отличие от системных потоков ОС, у которых стек фиксированного размера, стек горутины управляется рантаймом Go и изначально размещается в куче.
  • Динамический размер. При создании горутины ей выделяется небольшой стек (обычно 2 КБ). Если этого пространства становится недостаточно, рантайм Go автоматически выделяет новый, больший сегмент стека в куче и копирует в него старые данные. Это позволяет эффективно запускать сотни тысяч горутин одновременно.

2. Данные, аллоцируемые горутиной

Когда код внутри горутины создает переменные (например, через make, new или композитные литералы), место их аллокации (стек горутины или общая куча) определяется анализом побега (escape analysis), так же, как и в обычной функции.

  • На стеке горутины: Если переменная не используется за пределами горутины и ее жизненный цикл ограничен работой горутины, она будет размещена на стеке этой горутины.
  • В куче (heap): Если на переменную берут указатель, который передается в другую горутину (через канал) или она "переживает" функцию, в которой создана, она "сбегает" в кучу.

Итог:

  • Сам стек горутины — всегда в куче.
  • Данные внутри горутины — на стеке горутины (если не "сбегают") или в общей куче (если "сбегают").
func main() {
    go func() {
        // Переменная 'x' скорее всего будет на стеке этой горутины.
        x := 10

        // Слайс 'data' будет аллоцирован в куче, так как make
        // для слайсов по умолчанию выделяет память в куче
        // (если компилятор не докажет обратное).
        data := make([]byte, 1024)

        _, _ = x, data
    }()
    // ... ожидание завершения горутины
}