此链接:http://research.swtch.com/godata
它说(切片的第三段):
因为切片是多字结构,而不是指针,切片 操作不需要分配内存,甚至不需要分片 标题,通常可以保留在堆栈中。这种表示 使切片与使用显式指针一样便宜 C中的长度和长度。最初将切片表示为指针 到上面显示的结构,但这样做意味着每一片 操作分配了一个新的内存对象。即使使用快速分配器, 这为垃圾收集器创造了许多不必要的工作,并且 我们发现,就像上面的字符串一样,避免了程序 切片操作有利于传递显式索引。删除 间接和分配使得切片足够便宜以避免 在大多数情况下传递显式索引。
什么...?为什么不分配任何内存?如果是多字结构或指针?它不需要分配内存吗?然后它提到它最初是指向该切片结构的指针,它需要为新对象分配内存。为什么现在不需要这样做?非常困惑
答案 0 :(得分:5)
切片操作不需要分配内存。
“切片操作”是指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 &example
或otherFunc(&example)
或以其他方式允许指向此的指针时,才会强制编译器在堆上分配结构(或切片头)。
然后它提到它最初是指向该切片结构的指针,它需要为新对象分配内存。为什么现在不需要这样做?
想象一下,你没有做过上述事情:
example2 := &SliceHeader{…same…}
// or
example3 := new(SliceHeader)
example3.Data = …
example3.Len = …
example3.Cap = …
即。类型为*SliceHeader
而不是SliceHeader
。
根据你提到的内容,这实际上就是切片(pre Go 1.0)。
以前也必须在堆上分配example2
和example3
。这就是所谓的“新对象的记忆”。我认为现在转义分析会尝试将这两个放在堆栈上,只要指针保持在函数的本地,这样它就不再那么大了。无论哪种方式,避免一个级别的间接是好的,与复制指针和重复解除引用相比,复制三个整数几乎总是更快。
答案 1 :(得分:2)
每种数据类型在初始化时都会分配内存。在博客中,他明确提到了
切片操作不需要分配内存。
他是对的。现在看,how slice works in golang。
切片保存对基础数组的引用,如果您指定一个 切片到另一个,都指向同一个数组。如果一个函数需要一个 切片参数,它对切片的元素所做的更改 对调用者可见,类似于将指针传递给 底层数组。