С весны на собесах стабильно спрашивают про Green Tea. И ответ, который я слышу в девяти случаях из десяти, звучит так: «ну, он на 40% быстрее». Дальше начинаешь уточнять — быстрее что? — и человек плывёт.
Проценты там действительно есть. Просто относятся они не к тому, о чём все думают. Разберём по косточкам, что внутри и откуда эти цифры берутся.
Начнём с уборщика
Представьте комнату, полную игрушек. Часть ещё нужна, часть — уже нет. Кто‑то должен ходить и выбрасывать ненужное, иначе комната зарастёт.
В Go этим занимается сборщик мусора. Программа создаёт данные, перестаёт ими пользоваться, сборщик приходит и освобождает место.
10 февраля 2026 вышел Go 1.26, и уборщик там работает по‑новому. Подход называется Green Tea, включён по умолчанию, кода менять не надо.
Как это работало раньше
Данные в памяти связаны ссылками: один объект «знает» про другой, тот — про третий. Получаются нити, тянущиеся от игрушки к игрушке.
Старый сборщик шёл по этим нитям. Взял объект, пометил как нужный, посмотрел, на кого он ссылается, пошёл дальше. Объект за объектом, пока не обойдёт всё живое.
С логикой тут всё в порядке, проблема не в ней. Проблема в том, что объекты лежат в памяти вразброс. Первый в начале, второй далеко, третий снова где‑то не там. Уборщик, идущий по нитям, скачет по всему дому: из спальни в кухню, оттуда на чердак, потом обратно в спальню.
Почему беготня дорого стоит
У процессора есть маленькая быстрая память под рукой — кэш. Как карман: что в кармане, достаёшь мгновенно. А есть большая медленная память, это уже кладовка в другом конце дома.
Процессору нужны данные — он сначала смотрит в карман. Не нашёл — идёт в кладовку. Поход в кладовку обходится до ста раз дороже.
А теперь сопоставьте: объекты разбросаны, каждый переход по нити — прыжок в случайное место. Почти каждый шаг старого уборщика оказывался походом в кладовку.
Команда Go разложила расход по полочкам:
-
около 90% времени сборщика уходит на пометку живых объектов, и только 10% — на само освобождение памяти;
-
из этого времени пометки не меньше 35% процессор просто стоит и ждёт данные из памяти;
-
программы на Go нередко тратят на сборку мусора 20% процессорного времени и больше.
В блоге Go это описано через дорогу: процессор хочет ехать по шоссе, а старый алгоритм гонит его по городским улицам. Не видно, что за поворотом, светофоры, пешеходы. Неважно, какой у вас мотор, если разогнаться негде.
Что придумали: страницы вместо объектов
Идея умещается в одну строчку:
Работать со страницами, а не с отдельными объектами.
Про слово «страница» сразу оговорюсь, потому что тут все спотыкаются (я в том числе спотыкался). В Go страница — это блок памяти в 8 КиБ, и это внутренняя единица самого Go. С размером страницы операционной системы она не связана никак, блог Go специально это подчёркивает. Каждая такая страница хранит объекты одного размера.
Дальше механика такая. В очереди работы лежат страницы, а не объекты — записей становится в разы меньше. У каждого объекта появляется второй бит пометки: раньше был один («увидели»), теперь два («увидели» и «просканировали»). Нашли ссылку на объект — кладём в очередь всю страницу целиком и ставим объекту бит «увидели».
Главный трюк — не спешить
Вот эту часть в пересказах обычно теряют, а она и есть самое интересное.
Старый сборщик работал как стопка: положил сверху — сразу взял сверху. Green Tea работает как очередь: положил в конец — возьмёшь нескоро.
Зачем так? Пока страница ждёт своей очереди, на ней накапливаются новые найденные объекты. И когда до неё доходит дело, сборщик обрабатывает не один объект, а сразу все накопившиеся — подряд, в том порядке, в каком они лежат в памяти. Одна и та же страница может попадать в очередь несколько раз за цикл, и это нормально, так и задумано.
Медлительность тут не побочный эффект, а собственно механизм.
Почему «подряд» решает
В процессоре есть штука под названием prefetcher. Он смотрит, как вы читаете память, и если видит, что чтение идёт последовательно — подгружает следующую порцию заранее, пока вы возитесь с текущей. Данные приходят до того, как их запросили, ждать нечего.
Но угадывать он умеет только последовательное чтение. При прыжках по случайным адресам угадывать нечего.
Старый сборщик от него не получал ничего. Green Tea получает всё. Плюс сами пометки страницы теперь чаще оказываются в кэше, а короткая очередь работы означает меньше конфликтов между ядрами.
Векторы: читать пачками
Раз чтение стало предсказуемым, открылась ещё одна дверь.
У современных процессоров есть векторные инструкции — обрабатывают не одно значение за раз, а сразу пачку. В Go 1.26 такое ускорение добавили для x86 начиная с Intel Ice Lake и AMD Zen 4. Регистры там шириной 512 бит, и этого хватает, чтобы все пометки целой страницы поместились в пару регистров прямо в процессоре. Плюс у этих процессоров есть отдельная инструкция для битовых операций, которая делает ключевой шаг сканирования за считаные такты.
Со старым алгоритмом такое было невозможно в принципе: объекты разных размеров, работы то на два бита, то на десять тысяч. Векторизовать нечего.
Прибавка — ещё около 10% сверх основного выигрыша. На процессорах постарше остаётся только выигрыш от последовательного чтения, он поменьше, но тоже есть.
Теперь честно про 10–40%
Возвращаемся к тому, с чего начали.
10–40% — это сокращение времени, которое тратит сборщик мусора. Не времени работы вашей программы.
Пример прямо из блога Go: если приложение проводит в сборщике 10% процессорного времени, экономия составит от 1% до 4% общего потребления CPU. Наиболее частый результат — около 10% от времени GC, то есть ближе к нижней границе диапазона.
Проценты бесплатные, их дают просто за обновление версии, и это хорошо. Но фраза «Go 1.26 ускорил мой сервис на 40%» — это не про Green Tea.
Что менять в коде
Ничего. Green Tea включён по умолчанию, обновляете Go, пересобираете проект, получаете выигрыш.
Если понадобится вернуть старое поведение, отказ делается на этапе сборки:
GOEXPERIMENT=nogreenteagc go build ./...
Обратите внимание, что это флаг сборки, а не запуска — подставить его перед готовым бинарником бесполезно, ничего не изменится.
И штука эта временная. В release notes Go 1.26 прямо написано, что отказ планируют убрать в Go 1.27. Так что закладываться на него в долгую не стоит. Если всё‑таки пришлось его включить из‑за просадки производительности, команда Go просит завести issue — им как раз нужны такие случаи.
Когда Green Tea не помогает
Про это обычно молчат.
Green Tea стоит на предположении, что на странице удастся накопить достаточно объектов, чтобы окупить само накопление. Когда куча устроена регулярно — объекты одного размера на похожей глубине — всё отлично.
Но бывают нагрузки, где на страницу раз за разом приходится ровно один объект. Тогда вы платите за накопление и не получаете с него ничего, и результат может оказаться хуже, чем на старом алгоритме. В реализации есть отдельная обработка таких страниц, просадку она смягчает, но не убирает совсем.
Порог при этом оказался неожиданно низким: по словам команды, выигрыш появляется, даже если за заход обрабатывается всего 2% страницы.
Отдельно: коротким утилитам всё это почти ничего не даст, там сборщик и так толком не работает. И на процессорах без векторной поддержки прибавки в 10% не будет.
Есть ещё ограничение, которое Green Tea не решает и не пытался решать. Сборщик мусора в Go не двигает объекты по памяти. Если на странице остался жить хоть один объект, вся страница продолжает занимать место. Программа с сильно разреженной кучей упрётся именно в это, и никакая скорость сканирования не спасёт.
Как проверить у себя
Всем цифрам из статей, включая эту, верить не обязательно. Проще померить.
# Green Tea (по умолчанию в 1.26)go build ./... && GODEBUG=gctrace=1 ./your-app# то же самое со старым сборщикомGOEXPERIMENT=nogreenteagc go build ./... && GODEBUG=gctrace=1 ./your-appgo test -bench=. -benchmem
Снимать стоит долю процессорного времени на GC, задержки на хвосте (p99) и скорость аллокаций — под своей реальной нагрузкой, а не на синтетике. И понаблюдать пару суток: хвостовые задержки любят вылезать не сразу.
Что мне в этой истории нравится — никакого нового хитрого алгоритма тут нет. Тот же mark‑sweep, что и был. Просто кто‑то посмотрел, как на самом деле устроено железо под ногами, и решил не спешить там, где все привыкли спешить.
А на собесе теперь есть что ответить, кроме «он на 40% быстрее».
Статья выросла из одного урока моего курса Go Senior Interview на Stepik. Курс бесплатный, там разобраны остальные части рантайма — планировщик, escape‑анализ, интерфейсы, дженерики, context — в том же формате, с квизами в стиле реальных собеседований.
Найдёте ошибку или неточность — напишите в комментариях, поправлю и здесь, и в курсе.
Источники
-
The Green Tea Garbage Collector — блог Go, 29 октября 2025. Майкл Книшек и Остин Клементс, по докладу с GopherCon 2025
-
Go 1.26 Release Notes — раздел Runtime
-
runtime: green tea garbage collector — issue #73581 — обсуждение дизайна
-
A Guide to the Go Garbage Collector — про настройку частоты сборок
ссылка на оригинал статьи https://habr.com/ru/articles/1063470/