11 вопросов
Внутреннее устройство Go: сборщик мусора (tri-color mark & sweep), escape analysis, модель GMP (Goroutine-Machine-Processor), стек горутин и GOMAXPROCS. Частые вопросы на senior-собеседованиях.
Go использует concurrent tri-color mark & sweep. Объекты делятся на белые (кандидаты на удаление), серые (в процессе обработки) и чёрные (достижимые). GC работает конкурентно с программой, минимизируя stop-the-world паузы (обычно < 1 мс).
Подробнее →Escape analysis при компиляции определяет, может ли переменная остаться на стеке или должна быть размещена в куче. Если переменная 'убегает' из функции (например, возвращается указатель), она размещается в куче. go build -gcflags='-m' покажет решения компилятора.
Подробнее →Стек: автоматическое выделение/освобождение при входе/выходе из функции без участия GC. Выделение - одна инструкция (сдвиг указателя стека). Куча требует аллокатора и GC для освобождения. В Go стек горутины растёт динамически (начинается с 2-8 КБ).
Подробнее →Горутина начинает с ~2-8 КБ стека, который растёт/сжимается динамически. Поток ОС обычно занимает 1-8 МБ фиксированно. Поэтому можно создать миллионы горутин, но не миллионы потоков ОС. Это делает горутины очень дешёвыми в создании.
Подробнее →GOMAXPROCS задаёт число P (logical processors) - максимум потоков, одновременно исполняющих Go-код. По умолчанию равно числу CPU ядер. Горутин может быть гораздо больше - планировщик мультиплексирует их на P потоков. Менять GOMAXPROCS обычно не нужно.
Подробнее →GOGC=100 (default): GC запустится, когда куча вырастет на 100% от размера живых объектов после предыдущего цикла. GOGC=off отключает GC.
Подробнее →GOMEMLIMIT - мягкий лимит. GC учащается при приближении к нему, но не гарантирует, что лимит не будет превышен. Заменил паттерн memory ballast.
Подробнее →G (Goroutine) - горутина, M (Machine) - поток ОС, P (Processor) - логический процессор с локальной очередью горутин. Каждый P привязан к одному M. Горутины из очереди P исполняются на M. Work stealing: если очередь P пуста, он ворует горутины у других P.
Подробнее →До GOMEMLIMIT аллоцировали большой []byte (ballast), чтобы GC считал живую память больше и запускался реже. GOMEMLIMIT решил проблему элегантнее.
Подробнее →Netpoller использует epoll (Linux) / kqueue (macOS) для мультиплексирования I/O. Горутина "блокируется" на чтении из сокета, но поток ОС освобождается для других горутин.
Подробнее →Work stealing: каждый P имеет локальную очередь горутин. Когда она пуста, P пытается украсть половину горутин из очереди другого P. Это обеспечивает равномерную загрузку процессоров.
Подробнее →