避免内存逃逸需要遵循如下两个原则:
下面通过举例,来进一步论证逃逸分析的原则,加深一下理解
我们可以使用这个命令go build -gcflags '-m -m -l' go文件名
,来查看逃逸分析的结果。
func main() {
num := 1
fmt.Println(num)
}
原因分析:
func Println(a ...interface{}) (n int, err error)
,这个函数的入参是interface类型
,编译阶段无法确定其具体的参数类型,所以内存分配到堆上
func main() {
_ = test()
}
func test() *int {
num := 10
return &num
}
原因分析:
变量num在函数外部存在引用,函数退出时栈中的内存(栈帧)已经释放,但引用已经被返回,如果通过引用地址取值,在栈中是取不到值的,所以Go为了避免这个情况,会将内存分配到堆上。
func main() {
//不会逃逸
s1 := make([]int, 10, 10)
for i := 0; i < 10; i++ {
s1[i] = i
}
//会逃逸
s2 := make([]int, 10000, 10000)
for i := 0; i < 10000; i++ {
s2[i] = i
}
}
原因分析:
切片容量过大时,会产生逃逸,内存分配到堆上;容量小时,不会逃逸,内存分配依赖在栈上。
func main() {
num := 10
s := make([]int, num, num)
for i := 0; i < num; i++ {
s[i] = i
}
}
原因分析:
切片的长度和容量,虽然通过声明的变量num来指定了,但在编译阶段是未知的,并不确定num的具体值,所以会逃逸,将内存分配到堆上。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。