Go语言的逃逸分析是怎么进行的
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。
非常期待和您一起在这个小小的网络世界里共同探索、学习和成长。💝💝💝 ✨✨ 欢迎订阅本专栏 ✨✨
前言
小郑最近在准备Go语言的面试题,通过github和b站等各种学习网站上学习go语言的八股文,并且整理出自己觉得面试可能会问到的知识点,希望通过做笔记的方式来巩固自己的知识点,并且也希望可以帮助到大家在面试的时候更加得心应手一些,那么从现在开始,和我一起加入八股学习之旅吧!
回答重点
逃逸分析是编译器优化的一部分,用来决定对象应该分配在栈上还是堆上。
在 Go 语言中,编译器会在编译期间进行逃逸分析,通过分析代码中的变量确定它们是否会“逃逸”出当前的作用域。
如果一个变量在函数或方法内被创建,但在函数外部仍然被引用,那么它将被称为“逃逸”,需要分配到堆上;否则,它将被分配在栈上。
栈分配和堆分配的区别:
栈分配的好处是分配和释放内存的开销非常小,速度快。
堆分配需要依赖垃圾回收器(GC)来管理内存,因此开销相对较大。
逃逸分析的过程
逃逸分析由编译器在编译期间进行,它检查每一个变量的使用情况。编译器根据变量的作用范围、生命周期、以及变量是否被传递给其他协程或返回到外部等来确定其是否逃逸。
主要的原则包括:
- 若变量的生命周期超出当前函数,则视为逃逸。
- 若变量被引用并存储到堆上,则视为逃逸。
变量本来应该存在栈上(即是局部的,生命周期只在当前函数内),但是它被引用到堆上,意味着它的生命周期会超出当前函数的作用域,可能会继续存在下去。这就发生了“逃逸”。
- 若变量被传递给外部函数、方法或 goroutine,且存活时间可能超过当前函数,则视为逃逸。
package mainimport "fmt"func escapeExample() *int {x := 42 // 局部变量 xreturn &x // 返回 x 的地址,x 发生逃逸,分配到堆上
}func stackExample() int {x := 42 // 局部变量 xreturn x // x 没有逃逸,分配在栈上
}
由于 Go 语言的内存模型,如果你将一个局部变量的地址返回,这个变量的生命周期就会被延长。
Go 编译器会认为 x 的生命周期不能仅限于函数 escapeExample 的作用域,因为返回的地址可能会在函数外部被引用。因此,Go 会把 x 从栈上移动到堆上,并确保它的生命周期持续足够长。
return x 返回了 x 的值,而不是返回 x 的地址。 在这种情况下,x 的值被复制到了调用者的栈上,这意味着 x 并没有逃逸到堆上。它依然只在函数内部有效,并且在函数调用结束后会被销毁。
逃逸分析的优化技巧
返回指针,闭包捕获,接口赋值,动态类型转换等会导致变量逃逸。
1,避免不必要的指针返回:如果可能,返回值而不是返回指针。
2,减少闭包对变量的引用:避免在闭包中使用外部变量,尽量将变量传递给闭包。
3,游免接口赋值:使用具体类型代营接口,减少逃逸到堆的可能性。
❤️❤️❤️小郑是普通学生水平,如有纰漏,欢迎各位大佬评论批评指正!😄😄😄
💘💘💘如果觉得这篇文对你有帮助的话,也请给个点赞、收藏下吧,非常感谢!👍 👍 👍