golang中的切片不分配任何内存?

时间:2015-03-22 15:54:18

标签: pointers go slice

此链接:http://research.swtch.com/godata

它说(切片的第三段):

  

因为切片是多字结构,而不是指针,切片   操作不需要分配内存,甚至不需要分片   标题,通常可以保留在堆栈中。这种表示   使切片与使用显式指针一样便宜   C中的长度和长度。最初将切片表示为指针   到上面显示的结构,但这样做意味着每一片   操作分配了一个新的内存对象。即使使用快速分配器,   这为垃圾收集器创造了许多不必要的工作,并且   我们发现,就像上面的字符串一样,避免了程序   切片操作有利于传递显式索引。删除   间接和分配使得切片足够便宜以避免   在大多数情况下传递显式索引。

什么...?为什么不分配任何内存?如果是多字结构或指针?它不需要分配内存吗?然后它提到它最初是指向该切片结构的指针,它需要为新对象分配内存。为什么现在不需要这样做?非常困惑

2 个答案:

答案 0 :(得分:5)

展开Pravin Mishra's answer

  

切片操作不需要分配内存。

“切片操作”是指s1[x:y]之类的内容,而不是切片初始化或make([]int, x)。例如:

var s1 = []int{0, 1, 2, 3, 4, 5} // <<- allocates (or put on stack)
s2 := s1[1:3]                    // <<- does not (normally) allocate

也就是说,第二行类似到:

type SliceHeader struct {
        Data uintptr
        Len  int
        Cap  int
}
…
example := SliceHeader{&s1[1], 2, 5}

通常像example这样的局部变量会被放到堆栈中。就像这样做而不是使用结构:

var exampleData            uintptr
var exampleLen, exampleCap int

那些example*变量进入堆栈。 只有当代码执行return &exampleotherFunc(&example)或以其他方式允许指向此的指针时,才会强制编译器在堆上分配结构(或切片头)。

  

然后它提到它最初是指向该切片结构的指针,它需要为新对象分配内存。为什么现在不需要这样做?

想象一下,你没有做过上述事情:

example2 := &SliceHeader{…same…}
// or
example3 := new(SliceHeader)
example3.Data = …
example3.Len = …
example3.Cap = …

即。类型为*SliceHeader而不是SliceHeader。 根据你提到的内容,这实际上就是切片(pre Go 1.0)。

以前也必须在堆上分配example2example3。这就是所谓的“新对象的记忆”。我认为现在转义分析会尝试将这两个放在堆栈上,只要指针保持在函数的本地,这样它就不再那么大了。无论哪种方式,避免一个级别的间接是好的,与复制指针和重复解除引用相比,复制三个整数几乎总是更快。

答案 1 :(得分:2)

每种数据类型在初始化时都会分配内存。在博客中,他明确提到了

  

切片操作不需要分配内存。

他是对的。现在看,how slice works in golang

  

切片保存对基础数组的引用,如果您指定一个   切片到另一个,都指向同一个数组。如果一个函数需要一个   切片参数,它对切片的元素所做的更改   对调用者可见,类似于将指针传递给   底层数组。