为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
墨色风雨 2021-09-27 10:04:20
此链接:http : //research.swtch.com/godata它说(切片部分的第三段):因为切片是多字结构,而不是指针,切片操作不需要分配内存,甚至不需要分配内存,切片头通常可以保存在堆栈中。这种表示使得切片的使用与在 C 中传递显式指针和长度对一样便宜。Go 最初将切片表示为指向上述结构的指针,但这样做意味着每个切片操作都分配了一个新的内存对象。即使使用快速分配器,这也会为垃圾收集器带来大量不必要的工作,而且我们发现,就像上面的字符串一样,程序避免了切片操作,而转而传递显式索引。删除间接和分配使切片足够便宜,以避免在大多数情况下传递显式索引。什么...?为什么它不分配任何内存?如果是多字结构还是指针?不需要分配内存吗?然后它提到它最初是指向该切片结构的指针,并且需要为新对象分配内存。为什么现在不需要这样做?非常困惑
查看完整描述

2 回答

?
慕标琳琳

TA贡献1830条经验 获得超9个赞

扩展Pravin Mishra 的回答:


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


“切片操作”指的是诸如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}

通常像exampleget这样的局部变量被放入堆栈。就像这样做而不是使用结构一样:


var exampleData            uintptr

var exampleLen, exampleCap int

这些example*变量进入堆栈。只有当代码确实return &example或otherFunc(&example)以其他方式允许指向 this 的指针转义时,编译器才会被迫在堆上分配结构(或切片头)。


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


想象一下,你所做的不是上面的:


example2 := &SliceHeader{…same…}

// or

example3 := new(SliceHeader)

example3.Data = …

example3.Len = …

example3.Cap = …

即类型是*SliceHeader而不是SliceHeader。根据您提到的内容,这实际上是切片过去的样子(Go 1.0 之前)。


它也曾经是这两个example2,并example3会对堆进行分配。这就是所指的“新对象的内存”。我认为现在转义分析将尝试将这两个都放入堆栈,只要指针保持在函数的本地,所以它不再是一个大问题。无论哪种方式,避免一级间接都是好的,与复制指针并重复取消引用相比,复制三个整数几乎总是更快。


查看完整回答
反对 回复 2021-09-27
?
ibeautiful

TA贡献1993条经验 获得超5个赞

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

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

他是对的。现在看看slice 在 golang 中是如何工作的。

切片保存对底层数组的引用,如果将一个切片分配给另一个切片,则两者都引用同一个数组。如果一个函数接受一个切片参数,它对切片元素所做的更改将对调用者可见,类似于传递一个指向底层数组的指针。


查看完整回答
反对 回复 2021-09-27
  • 2 回答
  • 0 关注
  • 262 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信