Как устроен и как растет стек горутины в Go?

Ответ

Каждая горутина в Go имеет свой собственный стек, который, в отличие от системных потоков в C++ или Java, является легковесным и управляется Go runtime.

Устройство и рост стека


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


  2. Механизм роста (Contiguous Stacks): Современные версии Go (начиная с 1.4) используют модель непрерывных стеков. Рост происходит следующим образом:

    • Проверка (Stack Guard): Перед вызовом функции Go runtime выполняет быструю проверку: достаточно ли на стеке места для этой функции.
    • Копирование стека: Если места не хватает, выполнение горутины приостанавливается. Runtime выделяет новый блок памяти, в два раза больше старого стека, и копирует туда всё содержимое старого стека.
    • Обновление указателей: Все указатели внутри стека (например, на локальные переменные) обновляются, чтобы указывать на новые адреса в новом блоке памяти.
    • Возобновление: Горутина возобновляет свою работу, используя уже новый, расширенный стек.

  3. Сжатие стека: Если стек горутины сильно вырос, а затем перестал использоваться (например, после выхода из глубокой рекурсии), сборщик мусора может его "ужать", скопировав в блок памяти меньшего размера.


Преимущества

  • Эффективность памяти: Позволяет запускать огромное количество горутин.
  • Отсутствие Stack Overflow: Этот механизм практически исключает классические ошибки переполнения стека, так как он растет по мере необходимости.
// Эта функция вызовет многократное расширение стека,
// но не приведет к ошибке Stack Overflow, как в других языках.
func deepRecursion(n int) {
    if n == 0 {
        return
    }
    deepRecursion(n - 1)
}

func main() {
    go deepRecursion(1000000) // Работает без сбоя
}

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