Материал проходит вычитку — возможны неточности.
Урок 19 из 118

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 тратится во время сборки, а не в одной паузе. Подробнее о фазах и настройке — следующие уроки.

Задание · вопросы

Проверьте себя

Вопрос 1 из 3

Что такое корни в tri-color разметке?

Вопрос 2 из 3

Чёрный parent получает ссылку на белый child во время mark-фазы без write barrier. Что будет?

Вопрос 3 из 3

uintptr с адресом объекта удерживает объект живым?

Итоги

GC: куча, mark-sweep, tri-color; write barrier защищает от потери объектов при параллельном переписывании указателей. Паузы малы, но GC ест CPU во время сборки.

Наш сайт собирает куки. Чтобы тебе было удобнее им пользоваться. Нажимая на кнопку, ты даёшь разрешение собирать куки