Частые аллокации создают работу сборщику мусора. Снижать их нужно после профиля, потому что не каждая аллокация плоха: иногда она упрощает код и почти ничего не стоит.

Смотрим решения компилятора

go build -gcflags=-m ./...

Компилятор сообщает, какие значения уходят в кучу. Типичные причины:

  • возвращается указатель на локальное значение;
  • значение попадает в интерфейс;
  • срез или замыкание живёт дольше функции;
  • большой объект передаётся по значению.
локальное значение стек живет внутри вызова куча нужно после возврата

Компилятор смотрит на время жизни значения. Указатель сам по себе не означает кучу, а escape не всегда требует оптимизации.

Escape analysis не враг сам по себе. Нужна причина в горячем пути, а не исправление всех строк вывода.

Лишние копии

append может выделить новый массив. Если ёмкость известна, её задают заранее:

result := make([]string, 0, len(items))
for _, item := range items {
    result = append(result, item.Name)
}

strings.Builder уменьшает число временных строк при сборке. fmt.Sprintf удобен, но в горячем цикле может создавать лишние аллокации и отражения типов.

strings.Clone и bytes.Clone создают копию намеренно: она нужна, чтобы не держать большой исходный массив. Убирать такую копию без анализа нельзя.

Интерфейсы и значения

Передача большой структуры по значению копирует её. Указатель уменьшает копирование, но продлевает жизнь объекта. Поэтому оптимизация начинается с понимания владения, а не с замены всех значений указателями.

Передача значения в interface{} иногда приводит к выделению в куче. Здесь помогает сигнатура с конкретным типом или меньшее значение.

Pool

sync.Pool переиспользует буферы, но очищает их при возврате и не гарантирует хранение. Он полезен для частых одинаковых аллокаций после бенчмарка, а не как универсальное ускорение.

Проверка эффекта: allocs/op, B/op, доля GC в CPU и итоговая latency. Меньше аллокаций без улучшения latency - не всегда победа.

Коротко

  • Сначала benchmem и -gcflags=-m, затем изменения.
  • Ёмкость срезов и Builder убирают лишние выделения.
  • Копия иногда нужна для освобождения большого массива.
  • Пул используют только после доказанной выгоды.