Обновить

Комментарии 10

Главный вывод: не используйте ***, везде используйте C (указатели на int у вас получатся автоматом) :)

как-как работать? ::))

работать на перделе

Лайк за внимательность. Пасхалка, обожаю Yuri The Professional.

СЕТООООННННН!!!

В гугле используют в продакшен

Интересно. Но жопой чую прям склонение к использованию каналов (гы). В код не посмотрел, но кажется, что все построено именно на каналах - это позволит более четко управлять памятью и процессорными потоками

Посмотрел исходники go 1.25.5 в директории go/src/runtime.

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

Вот как на самом деле устроен Green Tea GC (файл mgcmark_greenteagc.go):

  1. Никаких chan:
    Использование каналов в недрах GC было бы самоубийством по производительности из-за оверхеда на локи и переключения контекста. Вместо этого там используются lock-free очереди и атомики.

    • localSpanQueue: кольцевой буфер (ring buffer) на 256 элементов для каждого процессора (P).

    • spanQueue: глобальная очередь с мьютексом для балансировки нагрузки.

  2. Главная идея — Локальность и Батчинг:
    Обычный GC работает по принципу "нашел указатель -> добавил в стек -> пошел дальше" (LIFO). Это размазывает доступ по памяти.
    Green Tea GC работает иначе (FIFO + Batching):

    • Когда он находит указатель, он не сканирует объект сразу.

    • Он помечает "инлайн-биты" (spanInlineMarkBits) прямо в странице памяти (span), где лежит объект.

    • Спан (страница) целиком ставится в очередь (spanQueue).

    • Когда до спана доходит очередь, GC сканирует все накопленные объекты на этом спане разом. Это и есть та самая "векторизация" логическая — процессор молотит данные, которые лежат рядом, горячими кэш-линиями.

  3. Work Stealing без каналов:
    Вместо передачи сообщений через каналы, реализован механизм кражи работы (spanQueueSteal). Если у одного процессора (P) кончились спаны для сканирования, он лезет в локальные очереди соседей и "ворорует" пачку спанов через атомики (CompareAndSwap).

  4. Странная арифметика:
    В коде много битовой магии: spanScanOwnership, or(spanScanOneMark), atomic.Or8. Это всё для того, чтобы несколько потоков могли параллельно помечать объекты на одной странице, не блокируя друг друга, а потом один "счастливчик" забирал страницу на сканирование.

Итог: Это не высокоуровневое управление через каналы, а низкоуровневая оптимизация доступа к памяти (Data Locality) и очередей задач, чтобы кормить процессор данными максимально плотно. Каналы бы тут только все замедлили.

Я имел в виду что с новым gc очень удобно использовать короткоживущие каналы, причем пулами

Это интересная мысль. Если под "пулами короткоживущих каналов" вы имеете в виду sync.Pool (или свой список), в котором лежат каналы для переиспользования, то вы попали в точку, но немного с другой стороны.

Тут работает не магия каналов, а тот самый эффект "однородной плотной кучи", который любит Green Tea GC.

Смотрите, почему это взлетит:

  1. Каналы в пуле = Стабильная куча
    Когда вы используете пул, вы превращаете "короткоживущие" каналы в долгоживущие объекты. Вы их не удаляете, а возвращаете в пул. Это создает в памяти огромный массив (или связный список) объектов одного типа и размера (hchan).

  2. hchan — это структура с указателями
    Внутри канал — это структура (buf, sendq, recvq, lock).

    type hchan struct {
        ...
        buf      unsafe.Pointer // указатель
        sendx    uint   // данные
        recvx    uint   // данные
        recvq    waitq  // указатели на sudog
        sendq    waitq  // указатели на sudog
        lock     mutex
    }
    

    Если у вас в памяти лежат тысячи таких структур рядом (потому что аллокатор Go старается класть объекты одного размера в одни спаны), для Green Tea GC это выглядит почти как тот самый PointerBlock из вашего бенчмарка.

  3. Векторизация сканирования
    Green Tea GC видит спан (страницу памяти), забитый структурами hchan. Он помечает этот спан целиком, ставит в очередь, а потом "пролетает" по нему, сканируя все каналы разом. Это гораздо эффективнее, чем если бы эти каналы были разбросаны по куче вперемешку со строками и JSON-ами.

Но есть нюанс:
Если вы не используете пул, а просто создаете make(chan) и бросаете его (реально короткоживущие), то Green Tea GC тут особо не поможет. Он ускоряет фазу Mark (сканирование живого). Если канал умер до начала GC, сканировать его не надо, его просто зачистит Sweep (или он переиспользуется аллокатором).

Вывод:
Идея использовать пулы каналов (Worker Pool pattern или просто реюз структур) под Green Tea GC — архитектурно верная. Вы создаете плотную, предсказуемую структуру памяти, которую новый GC прожует в 2 раза быстрее.

Искренне ваш, Gemini 3 Pro 🤖

Можешь сделать анализ изменений в gc golang 1.26 (поищи информацию в интернете). Отвечай технично, не забудь списки изменений, но нужно в дуже игрожура. Постарайся уложиться в размер поста в телеграме.

Привет, гики! 🛠 На связи ваш тех-обозреватель. Пока все ждали февральского релиза, Go 1.26 уже выкатил RC1, и там завезли не просто «косметику», а настоящий тюнинг движка. Главный герой патчноута — Green Tea GC.

Если в 1.25 это был экспериментальный «крафт», то теперь это дефолтный стандарт. Разбираемся, почему ваш бэкенд скажет вам спасибо.

🍵 Green Tea: Главный апгрейд GC

Старый алгоритм (Parallel Marking) работал как дотошный курьер: бегал по каждой ссылке отдельно. Green Tea меняет парадигму.

  • Блочное сканирование: Теперь GC сканирует память не отдельными объектами, а целыми страницами (8 KiB). Это дико заходит современному железу из-за кэш-локальности.

  • SIMD на службе: Если ваш сервак на AVX-512, ликуйте. Go 1.26 умеет использовать векторные инструкции для ускорения обхода памяти. Это дает еще +10% к производительности сверху.

  • Прощай, Lock Contention: В 1.25 были жалобы на конкуренцию за мьютексы в рантайме. В 1.26 это пофиксили — теперь даже при 2 млн RPS задержки стабильнее.

📊 Что в сухом остатке? (TL;DR)

  1. CPU Overhead: Снижение нагрузки на 10–40% на тяжелых аллокациях.

  2. Малые объекты: Аллокация объектов до 512 байт стала еще быстрее благодаря выделенным путям в компиляторе.

  3. CGO: Накладные расходы на вызовы C-кода упали на 30% без изменения самого кода.

Статейка родилась в муках творчества, при участии Gemini 3 Pro. 

А, так это он нагенерил "GC вынужден работать на перделе своих возможностей." ;-)

Креатив. Рад, что понравилось.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации