Зачем указывать емкость (capacity) при создании слайса?
Основная причина — минимизация количества аллокаций памяти и операций копирования, что напрямую влияет на производительность приложения.
1. Избегание лишних аллокаций
Когда мы добавляем элементы в слайс через append, и текущая емкость (cap) заканчивается, Go вынужден:
- Выделить в куче (heap) новый блок памяти (обычно в 2 раза больше предыдущего).
- Скопировать все элементы из старого массива в новый.
- Обновить указатель в дескрипторе слайса.
Если мы заранее знаем, что в слайсе будет, например, 1000 элементов, и создадим его как make([]int, 0, 1000), Go выделит память ровно один раз. Если же создать []int{} и заполнить его, произойдет около 10-12 переаллокаций и копирований в процессе роста.
2. Снижение нагрузки на Garbage Collector (GC)
Каждая переаллокация создает «мусор» — старый базовый массив, который больше не используется. Чем больше таких промежуточных массивов создается, тем чаще будет запускаться сборщик мусора, чтобы их очистить, потребляя ресурсы CPU.
3. Предсказуемое поведение (Side Effects)
Если несколько слайсов ссылаются на один и тот же базовый массив, append может вести себя по-разному:
- Если
len < cap,appendизменит базовый массив, что увидят и другие слайсы. - Если
len == cap,appendсоздаст новый массив, и связь между старым и новым слайсом разорвется.
Явное управление емкостью помогает избежать трудноуловимых багов при работе с под-слайсами (reslicing).
Сравнение в коде
// Плохо: если мы знаем, что элементов будет много
s := make([]int, 0)
for i := 0; i < 1000; i++ {
s = append(s, i) // Будет много аллокаций и копирований
}
// Хорошо: выделяем память один раз
s := make([]int, 0, 1000)
for i := 0; i < 1000; i++ {
s = append(s, i) // Память уже готова, работает мгновенно
}
Важный нюанс: len vs cap в make
Частая ошибка новичков — путать длину и емкость при инициализации:
make([]int, 100)— создает слайс из 100 элементов, заполненных нулями. Если делатьappend, 101-й элемент будет добавлен в конец, а первые 100 останутся нулями.make([]int, 0, 100)— создает пустой слайс, но с зарезервированной памятью под 100 элементов.appendначнет заполнять его с самого начала (с индекса 0).
Резюме
Указывать емкость нужно для оптимизации:
- Экономия CPU: меньше операций копирования данных.
- Экономия памяти: избегаем фрагментации и лишних аллокаций.
- Снижение GC Pressure: меньше работы для сборщика мусора.
Правило хорошего тона: Если ты заранее знаешь примерный размер данных (или хотя бы их верхнюю границу) — всегда инициализируй слайс с указанием cap.