微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

安得倚天抽宝剑——Go中new到底在堆还是栈中分配

安得倚天抽宝剑——Go中new到底在堆还是栈中分配

逃逸分析是什么?

在C/C++中,我们是使用malloc或new来从堆山取一块内存,怎么使用这块内存,完全取决于程序员,因此很容易发生内存泄漏。而Go语言会在两个地方给变量分配内存,虽然Go也是可以通过new来给变量分配内存,但是分配的这块内存,可能在堆上,也可能在栈上。从性能的角度出发,在栈上分配内存和在堆上分配内存,性能差异是非常大的。因此一个变量是在对上分配内存,还是在栈上分配内存,是需要编译器经过逃逸分析才能得出结论。

在编译原理中,分析指针动态范围的方法称为逃逸分析。当一个对象的指针被多个方法或线程引用时,我们称这个指针发生了逃逸。

逃逸分析存在的意义何在?

其实逃逸分析并不是专属于Go的“蜜糖”,Java也使用逃逸分析。

但是Java的逃逸分析有很多限制,对于不进行全局转义的对象,Java不会将堆分配替换为堆栈分配。然而,Java使用了另一种称为标量替换的技巧,它避免了将对象放在栈上的需要。本质上,它分解对象,并将其基本成员放在栈上。

Go的GC,让程序员可以不理解堆和栈也可以编写高效的业务,让编译器去和堆和栈打交道就行了…

使用逃逸分析后,如果编译器发现这个变量在该函数结束后不会再调用了,就会把这个变量分配到栈上,毕竟使用栈速度快、不会产生内存碎片。如果编译器发现某个变量在函数之外还有其他地方要引用,那么就把这个变量分配到栈上。

为什么不将变量全部分配到堆空间上呢?像C那样不是也挺好的吗?

这是因为堆不能像栈那样函数一结束就自动清理,会导致GC频繁工作,而通过逃逸分析,我们可以尽可能把变量分配到栈上,可以减少内存碎片,减少GC回收的时间,所以逃逸分析是Go用来减少GC压力的一个技巧。

Golang的逃逸分析怎么实现,方法和操作是怎样?

Golang的逃逸分析简单来说就是,如果一个变量的引用从声明它的函数中返出去了,则发生“逃逸”,因为它有可能在函数外被别的内容使用,所以必须分配到堆上。如果变量在函数外部没有被引用,那么就优先将这个变量放置在栈上。不过有如下几种特殊情况:

  • 函数调用其他函数
  • 引用作为结构体的成员变量
  • 切片和映射
  • Cgo指向变量的指针

还有一种情况,如果栈已经满了,或者放不下,自然只能放在堆上了。

参考资料

机械工业出版社《Go程序员面试笔试宝典》

Go并不需要Java风格的GC https://robberphex.com/go-does-not-need-a-java-style-gc/?utm_source=segmentfault&utm_medium=head

详解二:Go 语言机制之逃逸分析 https://zhuanlan.zhihu.com/p/137536970

Golang逃逸分析 https://www.jianshu.com/p/670ba8ed0685/

原文地址:https://cloud.tencent.com/developer/article/2123990

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐