← Назад к вопросам

С какого значения начинается стек в горутине

3.0 Senior🔥 141 комментариев
#Конкурентность и горутины#Основы Go

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Начальный размер стека горутины в Go

В языке Go каждая горутина начинает свою работу со стартовым стеком очень небольшого размера. Это одна из ключевых особенностей, обеспечивающих легковесность и эффективность горутин по сравнению с традиционными потоками ОС.

Конкретные значения и эволюция

Точный начальный размер стека не является фиксированной константой в спецификации языка, а определяется реализацией рантайма Go и менялся в разных версиях:

  1. В исторических версиях (до Go 1.2) размер начального стека составлял 4 КиБ (4096 байт).

  2. Начиная с Go 1.2 и в современных версиях (вплоть до 1.21 на момент написания), размер был уменьшен до 2 КиБ (2048 байт). Это было сделано для еще большей экономии памяти при массовом создании горутин.

    // В runtime/stack.go можно найти константу, определяющую начальный размер.
    // _StackMin в настоящее время равен 2048 байт для большинства систем.
    // Это минимальный размер стека, используемый при создании горутины.
    

Преимущества маленького стартового стека

  • Эффективное использование памяти: Возможность запускать миллионы горутин, не исчерпывая оперативную память.
  • Быстрое создание и уничтожение: Малый объем выделяемой памяти ускоряет эти операции.
  • Локализация кэша: Небольшие фрагменты памяти лучше укладываются в кэши процессора.

Механизм роста стека (Stack Growing)

Ключевой момент, компенсирующий малый начальный размер, — это механизм динамического (автоматического) роста стека. Когда горутине не хватает стековой памяти (например, при глубокой рекурсии или вызове функций с большим количеством аргументов/локальных переменных), рантайм Go автоматически выделяет новый, больший по размеру блок памяти для стека.

Важно: Стек копируется целиком в новое место. Указатели на объекты в старом стеке при этом корректно обновляются благодаря точной сборке мусора (precise GC) и сотрудничающим (cooperative) механизмам в рантайме.

package main

func recursiveFunction(counter int) {
    var buffer [256]int // Выделяем память в стеке
    if counter == 0 {
        return
    }
    recursiveFunction(counter - 1) // Рекурсивные вызовы могут спровоцировать рост стека
}

func main() {
    // Эта горутина начинает работу со стеком ~2КБ.
    go recursiveFunction(100)
    select {}
}

Сравнение с системными потоками

В противоположность горутинам, потоки ОС (например, в Linux) по умолчанию создаются со стеком значительного размера (часто от 2 до 8 МБ). Этот размер резервируется в виртуальной памяти сразу, что накладывает жесткие ограничения на максимальное количество параллельных потоков.

Как узнать и изменить размер (настройки окружения)

  1. Текущий размер можно косвенно наблюдать через отладчик или профилировщик (pprof), но простой константы для пользовательского кода нет.
  2. Минимальный размер стека для новых горутин можно задать через переменную окружения GODEBUG=stacksize=<байты>. Однако изменять это значение без крайней необходимости не рекомендуется.
    GODEBUG=stacksize=4096 go run main.go # Стартовый стек будет 4КБ
    
    Рантайм игнорирует значения меньше `_StackMin` (2048) или некратные 1024.

Итог: Стек горутины начинается с ~2 КиБ, что является фундаментальным design choice для их легковесности. Безопасность и отсутствие переполнения стека обеспечиваются не большим начальным запасом, а автоматическим механизмом роста, что позволяет достичь исключительного баланса между производительностью, безопасностью и эффективным использованием ресурсов.

С какого значения начинается стек в горутине | PrepBro