🗑 Сборщик мусора в Go: Скрытый налог на ваш CPU — 14 мая 2026 г. в 10:04:05.380
🗑 Сборщик мусора в Go: Скрытый налог на ваш CPU Если вы спросите джуна, как работает память в Go, он ответит: "Ну, там есть GC, он сам всё чистит". Сеньор же знает: GC - это не волшебная фея, это строгий налоговый инспектор. Он может не забирать ваши деньги (память), но он заберет ваше время (CPU). Давайте развеем главные мифы и заглянем под капот сборщика мусора в Go. Миф 1: GC вызывает долгие паузы (Stop-The-World) Выходцы из старой Java (или те, кто писал на Go до версии 1.5) до сих пор пугают детей долгими паузами, когда приложение буквально замирает на секунды. В современном Go это не так. Наш GC - это Concurrent Mark and Sweep (Конкурентная пометка и очистка). Фаза Stop-The-World (когда тормозится вообще всё) всё ещё есть, но она занимает доли миллисекунды. Как он работает (Трехцветный алгоритм): Представьте, что GC - это маляр, который красит ваши объекты: 1. Белые - объекты-кандидаты на удаление (изначально все такие). 2. Серые - объекты, до которых мы смогли дотянуться из корней (глобальные переменные, стеки горутин), но мы еще не проверили, на что ссылаются они сами. 3. Черные - живые объекты, которые мы проверили полностью. GC бегает по ссылкам, превращая серые объекты в черные, а новые найденные - в серые. Когда серых не остается, все оставшиеся белые объекты просто стираются из памяти. И главное - он делает это параллельно с работой вашего кода! В чем подвох? (Mark Assist) Если паузы такие короткие, почему мы вообще боремся за zero-allocation код? Потому что чудес не бывает. GC работает в фоне и забирает под себя до 25% CPU (четверть ваших потоков P). Но это еще не всё. Если ваше приложение генерирует мусор (белые объекты) быстрее, чем фоновый GC успевает их красить, планировщик включает режим паники - Mark Assist. Он буквально берет вашу горутину, которая обрабатывает важный HTTP-запрос пользователя, и говорит: "Слышь, прежде чем я дам тебе память, иди-ка помоги мне покрасить вон те объекты". В итоге ваш запрос, который обычно отрабатывает за 5мс, внезапно зависает на 50мс. Вы смотрите в логи и ничего не понимаете. 🔥 Senior Tip: Как этим управлять? В Go почти нет ручек для тюнинга GC, но есть две самые важные переменные окружения: 1. GOGC (по умолчанию 100). Означает "запускать GC, когда куча выросла на 100% от предыдущего размера". Если у вас куча свободной RAM, ставьте GOGC=500. Мусор будет копиться дольше, GC будет запускаться реже, CPU скажет спасибо. 2. GOMEMLIMIT (появилось в Go 1.19). Это "мягкий" лимит памяти. Позволяет сказать GC: "Не запускайся часто, пока мы не упремся в 2 ГБ, а вот если подошли к лимиту - чисти агрессивно". Это спасение от OOM (Out Of Memory) в Kubernetes. Мораль: Не бойтесь GC, но уважайте его труд. Используйте sync.Pool, заранее аллоцируйте слайсы (make([]int, 0, capacity)) и не передавайте огромные структуры по значению там, где это не нужно. #golang #underhood #performance #memory #architecture 👉 @golang_lib

