Ответ
Память, выделенная для слайса, освобождается сборщиком мусора (GC), когда на базовый (underlying) массив этого слайса больше не остается ссылок.
Сам по себе слайс — это легковесная структура (заголовок), состоящая из трех полей:
- Указатель на начало базового массива.
- Длина (length) — количество элементов в слайсе.
- Ёмкость (capacity) — общее количество элементов в базовом массиве от его начала.
Сборщик мусора отслеживает достижимость объектов в памяти. Пока хотя бы один слайс (или любая другая переменная) ссылается на базовый массив, этот массив считается достижимым и не будет удален.
Проблема утечки памяти при сабслайсинге
Частая ошибка возникает, когда из большого слайса создается маленький подслайс. Даже если вы используете только маленький срез, он все равно удерживает в памяти весь исходный большой массив.
func getSmallSlice() []int {
// Создаем большой массив и слайс на его основе
bigSlice := make([]int, 1000000)
// ... какая-то работа с bigSlice
// Возвращаем маленький срез из первых 10 элементов
smallSlice := bigSlice[:10]
return smallSlice
}
// После вызова getSmallSlice() переменная bigSlice исчезнет,
// но возвращенный smallSlice все еще ссылается на тот же
// гигантский массив из 1,000,000 элементов. Память не освободится.
Как правильно освободить память?
-
Обнуление ссылки: Если большой слайс больше не нужен, можно присвоить ему
nil
. Это разорвет ссылку, и если других ссылок на массив нет, GC сможет его собрать.bigSlice = nil // Теперь массив может быть собран
-
Копирование (предпочтительный способ): Создайте новый слайс нужного размера и скопируйте в него только необходимые данные. Это гарантирует, что вы не будете удерживать лишнюю память.
// Вместо return bigSlice[:10] result := make([]int, 10) copy(result, bigSlice[:10]) return result // Возвращаем новый слайс с собственным компактным массивом