← Назад к вопросам

Когда слайс очищается сборщиком мусора?

2.2 Middle🔥 121 комментариев
#Основы Go

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Когда слайс очищается сборщиком мусора в Go?

Сборщик мусора (GC) в Go очищает память, занятую слайсом, когда на него нет активных ссылок и он становится недостижимым из корней программы (стеков, глобальных переменных и других объектов). Однако важно понимать, что слайс в Go — это не самостоятельный объект, а структура данных, состоящая из трех компонентов: указателя на массив, длины (len) и емкости (cap). Поэтому вопрос очистки слайса разделяется на очистку структуры слайса и поддерживающего массива.

Ключевые моменты очистки памяти слайса

  1. Структура слайса очищается сразу, когда на нее нет ссылок. Она обычно небольшая (24 байта на большинстве архитектур) и размещается либо в стеке, либо в куче (если, например, слайс "убегает" из функции).
  2. Поддерживающий массив очищается только тогда, когда на него нет ссылок через любой слайс. Это наиболее важный аспект, поскольку массив может занимать значительную память.

Пример с несколькими слайсами

Рассмотрим ситуацию, когда два слайса ссылаются на один массив:

func main() {
    // Создаем исходный слайс
    original := make([]int, 1000) // Большой массив создается в куче
    // Создаем новый слайс, ссылающийся на часть того же массива
    slice2 := original[100:200]
    
    // Теперь есть две ссылки на один массив: через original и slice2
    
    original = nil // Убираем одну ссылку на массив
    // Массив НЕ очищается GC, потому что slice2 продолжает ссылаться на него!
    
    slice2 = nil // Убираем последнюю ссылку на массив
    // Теперь массив может быть очищен сборщиком мусора
}

В этом примере поддерживающий массив не будет очищен, пока обе ссылки (original и slice2) не будут удалены. Это демонстрирует, что GC отслеживает именно ссылки на базовый массив, а не на структуры слайсов.

Особенности при работе с функциями

При передаче слайса в функцию или возврате из функции часто создаются новые структуры слайса, но они обычно ссылаются на тот же массив:

func process(slice []int) []int {
    // Здесь создается новая структура слайса (в стеке), 
    // но она ссылается на тот же массив, что и исходный слайс
    return slice[10:] // Возвращаемая структура слайса ссылается на часть исходного массива
}

GC будет очищать эти временные структуры слайсов, но массив останется, если на него есть хотя бы одна "живая" ссылка.

Практическое влияние на разработку

  • Утечки памяти возможны, если вы сохраняете небольшую часть большого слайса, не осознавая, что весь исходный массив остается в памяти.
  • Для полного освобождения памяти большого массива нужно убедиться, что все слайсы, ссылающиеся на него, удалены (например, установлены в nil).
  • Сборщик мусора работает недетерминировано, поэтому очистка происходит не мгновенно после удаления ссылок, а во время очередного цикла GC.

Специальный случай: слайсы, созданные make([]T, 0)

emptySlice := make([]int, 0)

Такие слайсы часто ссылаются на предопределенный пустой массив в памяти, который никогда очищается GC (поскольку он используется всеми пустыми слайсами этого типа как оптимизация). Это не создает проблем, поскольку массив нулевого размера.

Таким образом, слайс "очищается GC" в два этапа: легкая структура слайса очищается быстро при потере ссылок, а тяжелый поддерживающий массив — только когда все слайсы, использующие его, становятся недостижимыми. Это поведение требует внимания при работе с большими данными, чтобы избежать незаметных утечек памяти.