在分析内存逃逸之前我们需要知道我们的内存空间的分布图,为内存逃逸的分析做一些铺垫,这是内存分布,当系统知道变量什么时候的生命周期和内存分配大小的时候我们都将其分配在栈区

在这里插入图片描述

(必知)分析内存逃逸之前我们需要几个知识点:

1.go在编译阶段确立逃逸,并不是在运行时

2.Golang 中的变量只要被引用就一直会存活,存储在堆上还是栈上由内部实现决定而和具体的语法没有关系。

3.逃逸分析是编译器用于决定变量分配到堆上还是栈上的一种行为

内存逃逸基本情况有6种,我们一种一种来进行分析

情况1:指针逃逸:

我个人理解是:指针逃逸的出现场景和c++中悬空指针的场景比较相似,但似乎由于语言的差别,又有所差别。

在这里插入图片描述
在这里插入图片描述

在go语言中,相同的场景,由于我们的go语言的特点,我们的这个引用不会在栈中被消除,而是存活到了堆区,见下图

在这里插入图片描述

所以在栈上释放内存的时候不会将c释放掉,c发生了逃逸。

结论:如果一个函数结束之后外部还有引用,那么必定被分配在堆中

情况2:栈空间不足逃逸

栈空间充足情况(见下图)

在这里插入图片描述

那么我们分配的空间大于栈区怎么办(不会分配失败,而是直接分配在堆区)

在这里插入图片描述

在分配时不能栈空间确定大小,不知道到底要开辟的空间是否超出限制也会发生逃逸

在这里插入图片描述

情况3:动态类型逃逸,interface类型可以代表任意类型,编译器不知道参数会是什么类型,只有运行时才知道,因此只能分配到堆上。

在这里插入图片描述

情况4,切片由于append操作,导致容量变大,就会被分配在堆上面

在这里插入图片描述

情况5,向chan中发送数据的指针或者包含指针的值,因为不知道什么时候被释放(根据自己的理解来写的,可能不太对,不过应该能解释过去,等笔者去查阅查阅资料再来补充)

在这里插入图片描述

*情况6:slices 中的值是指针的指针或包含指针字段。一个例子是类似[] string 的类型。这总是导致 slice 的逃逸。即使切片的底层存储数组仍可能位于堆栈上,数据的引用也会转移到堆中。(只知道结论,不知道为什么,待定,以后补充)