Golang逃逸分析-1

逃逸分析

逃逸是什么

当函数内部定义了一个局部变量,然后函数返回这个变量的指针,然后这个变量又在其他地方引用,就发生了逃逸。因为局部变量是在栈上创建的,当函数返回后会销毁

golang的逃逸分析

golang不同于c++,编译器会对局部变量进行分析,然后决定他们是否会分配到栈上还是堆上

  • 分配到堆上的开销很大,因为不能像栈一样可以自动清理,只能靠Go进行垃圾回收
  • 栈的分配更快,而分配到堆上首先需要去找一片内存块

通过逃逸分析,可以尽量把不需要分配到堆的变量直接分配到栈,堆上的变量少了会减轻堆内存分配的开销,同时减少垃圾回收的压力

怎么完成逃逸分析?

go的逃逸分析原则:如果函数返回了一个变量的引用,就会发生逃逸

逃逸了就放在堆上

1)如果变量在函数外部没有引用,则优先放到栈上

2)如果变量在函数外部存在引用,则必定放到堆上

也就是说一个变量取地址,这个变量也不一定在放堆上,因为他可能没有被引用

怎么确定逃逸?

go build -gcflags '-m -l' xxx.go 编译参数(-gcfl

-gcflags用于启用编译器支持的额外标志

-m 用于输出编译器的优化细节(包括使用逃逸分析这种优化)

-l 用于禁用函数的内联优化,防止逃逸被编译器通过内联彻底的抹除

什么情况发生逃逸

  1. 编译期间很难确定函数类型,比如如果函数参数为 interface{}
fmt.Println(a ...interface{})

解释fmt.Println 之类的底层系统函数,实现逻辑会基于interface{} 做反射,通过 reflect.TypeOf(arg).Kind() 获取接口对象的底层数据类型,创建具体类型对象时,会发生内存逃逸。由于 interface{} 的变量,编译时无法确定变量类型以及申请空间大小,所以不能在栈空间上申请内存,需要在 runtime 时动态申请,理所应当地发生内存逃逸。
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  1. 申请栈空间过大

    栈空间大小是有限的,如果编译时发现局部变量申请的空间过大,则会发生内存逃逸,在堆空间上给大变量分配内存

func main() {
   num := make([]int, 0, 10000)
   _ = num
}

.\main.go:404:13: make([]int, 0, 10000) escapes to heap   //发生逃逸

  1. Slice元素逃逸
type person struct {
   Name string
}

func main() {
   var num []*person
   p1 := &person{
      Name: "ss",
   }
   num = append(num, p1)
}

.\main.go:409:8: &person{...} escapes to heap

未指定slice的lencap时,slice自身未发生逃逸,slice的元素发生逃逸

因为slice会自动扩容,编译器也不知道slice元素大小,扩容后slice的元素可能会被分配到堆空间,因为元素可能不分配到栈上,所以slice整体也不分配到栈上

  1. 闭包

所谓闭包,就是函数与其所处环境捆绑的组合,也就是说,闭包可以让你在一个内部函数中访问到其外部函数的作用域

go
复制代码func Increase() func() int {
	n := 0
	return func() int {
		n++
		return n
	}
}

func main() {
	in := Increase()
	fmt.Println(in()) // 1
	fmt.Println(in()) // 2
}

Increase() 返回值是一个闭包函数,该闭包函数访问了外部变量 n,那变量 n 将会一直存在,直到 in 被销毁。很显然,变量 n 占用的内存不能随着函数 Increase() 的退出而回收,因此将会逃逸到堆上。

参考

https://juejin.cn/post/7193607980046041146?searchId=2023091418221995CEB63685D2793789C0

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值