GC: tri-color и write barrier
От аллокаций Миша перешёл к тому, кто их убирает. Сергей объяснил, как сборщик отличает живое от мёртвого, пока сервис продолжает отвечать клиентам, и нарисовал три цвета и барьер записи.
сборщик Go — конкурентный mark-sweep с tri-color разметкой, а write barrier не даёт потерять объект, пока программа параллельно переписывает указатели.
Что собирается и как
Сборщик работает только с кучей, но при маркировке он сканирует стеки как корни: указатели со стеков держат объекты живыми. Сами стековые переменные мусором не становятся — кадр функции освобождается целиком при возврате. Поэтому первая половина борьбы с давлением на GC решается ещё на этапе escape analysis — меньше значений в куче, меньше работы сборщику.
Go использует конкурентный mark-sweep с алгоритмом tri-color. Три цвета: белые объекты ещё не просмотрены, серые — просмотрены, но их ссылки не разобраны, чёрные — просмотрены полностью. Сборка начинается с корней (глобальные переменные, стеки горутин, регистры) — их красят в серый. Дальше волна: серый объект становится чёрным, а всё, на что он указывает, — серым. Когда серых не осталось, всё белое — мусор, его можно забирать. Живые объекты в текущей реализации никуда не переезжают: Go не уплотняет кучу, поэтому указатели на объекты кучи стабильны. Но это свойство реализации, а не гарантия языка, и стеки горутин при росте переезжают.
Write barrier
Маркировка идёт параллельно с работой программы — и в этом вся сложность. Программа может прямо во время mark-фазы создать новый объект или переписать указатель, связав чёрный объект с белым, — и сборщик потеряет этот белый объект, сочтя его мусором. Добавляет проблему и то, что свежевыделенные объекты рождаются сразу чёрными: иначе маркировка никогда не догнала бы поток аллокаций.
Write barrier — код, который компилятор встраивает в записи указателей: он дополнительно помечает серым то, на что указывает записываемое значение. Белый объект не может спрятаться за чёрным, и сборка остаётся корректной, хотя программа продолжает выполняться. Это упрощение — показана insertion-часть барьера: реальный барьер гибридный и дополнительно помечает перезаписываемое старое значение.
Что это значит для кода
Для разработчика из этого следует немногое, но важное: куча без уплотнения — свойство текущей реализации, и хранить адреса как uintptr без живой unsafe.Pointer-ссылки нельзя: uintptr не GC-корень и объект живым не удерживает; конкурентная маркировка — CPU на GC тратится во время сборки, а не в одной паузе. Подробнее о фазах и настройке — следующие уроки.
Проверьте себя
Что такое корни в tri-color разметке?
Чёрный parent получает ссылку на белый child во время mark-фазы без write barrier. Что будет?
uintptr с адресом объекта удерживает объект живым?
правильных ответов
GC: куча, mark-sweep, tri-color; write barrier защищает от потери объектов при параллельном переписывании указателей. Паузы малы, но GC ест CPU во время сборки.
10 000 ₽ · 60 минут · онлайн