Самое простое можно продемонстрировать с помощью простого выражения среза.
Давайте начнем с среза *int
указателей:
s := []*int{new(int), new(int)}
Этот срез имеет вспомогательный массив длиной 2, и он содержит 2 не nil
указателя, указывающих на выделенные целые числа (вне резервного массива).
Теперь, если мы изменим этот фрагмент:
s = s[:1]
Длина станет 1
.Массив поддержки (содержащий 2 указателя) не затрагивается, он содержит 2 действительных указателя.Несмотря на то, что мы сейчас не используем 2-й указатель, поскольку он находится в памяти (это резервный массив), указанный сборщик (который является пространством памяти для хранения значения int
) не может быть освобожден сборщиком мусора.
То же самое происходит, если вы «вырезаете» несколько элементов из середины.Если исходный фрагмент (и его резервный массив) был заполнен не nil
указателями, и если вы не обнуляете их (nil
), они будут сохранены в памяти.
Почему это не проблема с не указателями?
На самом деле, это проблема со всеми типами указателей и заголовков (например, срезами и строками), а не только с указателями.
Если у вас будет срез типа []int
вместо []*int
, то нарезка будет просто «скрывать» элементы типа int
, которые должны оставаться в памяти как часть резервного массива независимо от того,есть фрагмент, который содержит это или нет. Элементы не являются ссылками на объекты, хранящиеся за пределами массива, , в то время как указатели ссылаются на объекты, находящиеся вне массива.
Если срез содержит указатели и вы nil
их перед нарезкойоперации, если нет других ссылок на указанные объекты (если массив был единственным, содержащим указатели), они могут быть освобождены, они не будут сохранены из-за того, что все еще имеют срез (и, следовательно, резервный массив).
Обновление:
Если у вас есть фрагмент структур:
var bkSlice = []Books{Book1, Book2}
Если вы нарезаете его как:
bkSlice = bkSlice[:1]
Book2
станет недоступным через bkSlice
, но все еще будет в памяти (как часть резервного массива).
Вы не можете nil
это, потому что nil
не является допустимым значениемдля структур.Однако вы можете присвоить ему нулевое значение следующим образом:
bkSlice[1] = Book{}
bkSlice = bkSlice[:1]
Обратите внимание, что значение структуры Books
все еще будет в памяти, являясь вторым элементом массива поддержки,но эта структура будет нулевым значением и, таким образом, не будет содержать строковых ссылок, таким образом, оригинальный автор книги и строки заголовка могут быть собраны сборщиком мусора (если никто не ссылается на них; точнее, фрагмент байта ссылается из заголовка строки).
Общее правило является "рекурсивным": вам нужно только обнулить элементы, которые ссылаются на память, расположенную за пределами резервного массива. Так что если у вас есть фрагмент структур, которые имеют, например, int
поля, вам не нужно обнулять его, на самом деле это просто ненужная дополнительная работа.Если в структуре есть поля, которые являются указателями, или срезами, или, например, другой тип структуры, который имеет указатели или срезы и т. Д., То вам следует обнулить его, чтобы удалить ссылку на память вне резервного массива.