gc如何处理切片内存回收

时间:2018-09-01 07:51:09

标签: go garbage-collection slice

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的开头。

1 个答案:

答案 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