Ответ
Память для горутины можно разделить на две категории: собственный стек горутины и данные, которые горутина аллоцирует в процессе работы.
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
}()
// ... ожидание завершения горутины
}