Перейти к основному содержимому

Механизм перераспределения памяти в срезах (Slices Reallocation)

Определения

Len (Length) — текущее количество элементов в срезе. Cap (Capacity) — максимальное количество элементов, которое может вместить нижележащий массив (underlying array) без выделения новой памяти. Underlying Array — фактическая область памяти, где хранятся данные. Срез — это лишь дескриптор (указатель) на этот массив.

Поведение функции append()

Функция append реализует логику динамического расширения: Наличие емкости (Len < Cap): Новый элемент записывается в следующую свободную ячейку существующего массива. Все срезы, указывающие на этот же массив, «видят» изменения в общей области памяти (если их Cap позволяет до нее дотянуться). Дефицит емкости (Len == Cap): Среда исполнения Go выделяет новый, более крупный блок памяти (обычно в 2 раза больше предыдущего для небольших срезов). Старые данные копируются в новый массив. Возвращаемый срез теперь указывает на новый адрес в памяти. Разрыв связи: Старые срезы продолжают указывать на прежний (маленький) массив. Изменения в новом срезе больше не влияют на старые.

Оптимизация с помощью make()

Чтобы избежать лишних аллокаций (копирований) и непредсказуемого разрыва связей, используется функция make. Она позволяет заранее забронировать нужный объем памяти. Синтаксис:

// make([]Тип, Длина, Емкость)
users := make([]string, 0, 100)

Здесь len = 0 (срез пустой). Но cap = 100 (массив в памяти уже зарезервирован под 100 элементов). Результат: Первые 100 вызовов append будут работать молниеносно и гарантированно не изменят адрес среза в памяти.

Для повторения

Срез — это ссылка. Меняешь элемент в срезе — меняешь его в массиве. append — это риск. Если массив переполнен, срез «переедет» на новый адрес. copy() — это безопасность. Если нужна полная независимость данных, создавай новый срез через make и копируй данные вручную.