切片只是描述符(类似于小型结构的数据结构),如果不对其进行引用,则会对其进行正确的垃圾回收。
另一方面,切片的基本数组(描述符指向该数组)在所有切片之间 共享 ,这些切片通过切片来 共享 :引用自Go语言规范:Slice
Types:
切片一旦初始化,便始终与包含其元素的基础数组关联。因此,一个片与其阵列以及同一阵列的其他片共享存储。相反,不同的数组始终代表不同的存储。
因此,如果存在至少一个片,或保存数组的变量(如果通过对数组进行切片来创建片),则不会进行垃圾回收。
关于此的官方声明:
安德鲁·格朗德(Andrew Gerrand)撰写的博客文章 Go
Slices:用法和内部
原理明确说明了这种行为:
如前所述,对切片进行重新切片不会复制基础数组。 完整的数组将保留在内存中,直到不再被引用为止。
有时,这可能导致程序仅需要一小部分数据时就将所有数据保存在内存中。…
由于切片引用了原始数组, 因此只要将切片保留在垃圾收集器周围,就无法释放该数组 。
回到你的例子
虽然基础数组不会被释放,但是请注意,如果您将新元素添加到队列中,则内置
append函数有时可能会分配新数组并将当前元素复制到新元素上,但是复制只会复制切片的元素而不是整个基础数组!当发生这种重新分配和复制时,如果没有其他引用,则可能会“回收”旧数组。
另一个非常重要的事情是,如果从前面弹出一个元素,则切片将被切片并且不包含对弹出元素的引用,但是由于基础数组仍包含该值,因此该值也将保留在内存中(而不是只是数组)。建议每当从队列(切片/数组)中弹出或删除一个元素时,
始终将其 (切片中其相应的元素) 置零, 这样该值就不会不必要地保留在内存中。如果您的分片包含指向大数据结构的指针,则这一点变得尤为重要。
func PopFront(q *[]string) string { r := (*q)[0] (*q)[0] = "" // Always zero the removed element! *q = (*q)[1:len(*q)] return r}这里提到了Slice Tricks
Wiki页面:
删除但不保留订单
a[i] = a[len(a)-1]a = a[:len(a)-1]注意 如果元素的类型是一个 指针 或指针字段,其需要被垃圾收集一个结构,上述实施方式
Cut和Delete有潜在的 存储器泄露
的问题:其值的一些元素仍然由切片引用a并因此不能集。



