var a = [...]int{1,2,3,4,5,6}
s1 := a[2:4:5]
假设s1比a超出范围晚。 gc如何知道回收s1的基础数组a的内存?
考虑s1 spec的运行时表示形式
type SliceHeader struct {
Data uintptr
Len int
Cap int
}
GC甚至都不知道a的开头。
答案 0 :(得分:1)
Go使用标记清除扫描收集器作为当前实现。
根据算法,在多核机器gc
与程序一起在一个核上运行的情况下,将有一个根对象,其余的都是树状结构。
gc
将遍历树,当无法到达时,将其视为免费。
Go对象还具有此post中所述的对象元数据。
摘录:
由于我们没有标题,因此我们需要了解有关对象的一些信息。标记位保留在侧面,用于标记和分配。每个单词都有2位与之关联,以告诉您它是标量还是该单词内的指针。它还对对象中是否有更多的指针进行了编码,因此我们可以早晚停止扫描对象。
在此page中,切片部分的russ cox记录了go的切片(切片标头)是结构而不是结构指针的原因。
这是节选:
Go最初将切片表示为指向结构(切片标头)的指针,但是这样做意味着每个切片操作都会分配一个新的内存对象。即使使用快速分配器,它也为垃圾收集器创建了许多不必要的工作,并且我们发现,与字符串的情况一样,程序避免了切片操作而希望传递显式索引。在大多数情况下,删除间接寻址和分配可使切片便宜很多,从而避免传递显式索引。
数组的大小(长度)是其类型的一部分。 [1]int
和[2]int
类型是不同的。
要记住的一件事是go是面向值的语言,它们存储直接值而不是存储指针。
[3]int
,数组是go中的值,因此,如果传递数组,它将复制整个数组。
[3]int
这是一个值(作为一个整体)。
当a[1]
出现时,您正在访问值的一部分。
SliceHeader
数据字段将其视为数组的基点,而不是a[0]
据我所知:
当一个人请求a[4]
时,
a[0]+(sizeof(type)*4)
是计算得出的。
现在,如果您要通过切片s = a[2:4]
访问某些内容,
并且如果有人要求s[1]
,那是在要求什么,
a[2]+sizeof(type)*1