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

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

逃逸分析是什么?

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

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

image-20220825140137344

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

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

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

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

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

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

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

image-20220825140109870

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

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

  • 函数调用其他函数

  • 引用作为结构体的成员变量

  • 切片和映射

  • Cgo指向变量的指针

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

参考资料

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

Go并不需要Java风格的GC robberphex.com/go-does-not-need-a-...

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

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

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!