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

Ответ

Память для горутин выделяется и управляется средой выполнения Go (runtime), а не напрямую операционной системой. Основные моменты:

  1. Стек горутины: Каждая горутина получает собственный стек. Изначально он очень мал (обычно 2 КБ), что позволяет создавать сотни тысяч горутин без больших затрат памяти.

    • Этот стек выделяется в куче (heap), а не в стеке системного потока.
    • Стек может динамически расти и сжиматься по мере необходимости. Если горутине требуется больше места, среда выполнения выделяет новый, больший сегмент стека и копирует в него старые данные.
  2. Размещение переменных (Анализ ускользания): Компилятор Go выполняет анализ ускользания (escape analysis), чтобы решить, где разместить переменную — на стеке горутины или в общей куче.

    • На стеке: Локальные переменные, чьё время жизни не превышает время выполнения функции, размещаются на стеке. Это очень эффективно, так как память очищается автоматически при выходе из функции.
    • В куче: Если компилятор определяет, что на переменную будут ссылаться после завершения функции (например, её адрес возвращается или передаётся в другую горутину), переменная «ускользает» в кучу. Память в куче управляется сборщиком мусора (GC).
func main() {
    go func() {
        // 'a' будет размещена на стеке этой горутины
        a := 42 

        // 'b' будет размещена в куче, так как new() всегда выделяет память в куче.
        b := new(int) 
        *b = 100
    }()
}