Golang内存逃逸引发的面试考察点
什么是内存逃逸?
在go语言中每个goroutine都会有一个自己的栈区,每个栈区呢又会对应多个栈帧,每个栈帧就会对应一个函数,这个栈帧就是用来存储函数的局部变量、入参、返回地址等等。这些变量就会随着函数的运行结束而自动销毁。编译期会对相关变量会做一个分析,有些场景下变量就不会存入到栈帧而是会分配到堆上面,这个过程就是逃逸分析。
逃逸分析有什么作用?
帮助编译器优化内存分配和回收效率
哪些场景下会发生逃逸呢?
- 函数返回局部变量的指针
- 函数指针类型的入参
- 闭包访问的函数外部变量
- 动态变量类型
- 变量大小不确定时
- 栈空间不足存放变量内存时
有什么办法可以确认变量是否发生逃逸?
通过
go run -gcflags="-m -m" you_file.go
命令 PS:go run 和 go build都可以
堆栈分别有什么特点
栈
- 栈是一种自动分配和释放内存的数据结构,用于保存函数的局部变量、函数参数和函数调用返回时的临时数据
- 栈的分配和释放速度非常快,因为它只需要简单移动下栈指针
- 栈的大小在编译器就确定了且是固定不可改变的
- 栈上的变量的生命周期是与其对应函数的相对应的
- 栈上的内存是有限的并且是线程私有的不会存在并发访问问题
- 栈上存储的数据大小通常比较小,适用于存储基本数据类型和短期临时变量
堆
- 堆是动态分配的内存区域,用于存储程序运行时动态创建的数据结构体和对象等
- 堆的分配和释放稍微慢一点,因为需要在堆上进行复杂的内存管理操作,例如三色标记
- 堆的大小通常比较大,取决于运行时的需求,它的生命周期可以比较长
- 堆上的内存需要手动进行释放,不然会造成内存泄露
- 堆上的数据可以被多个线程共享,因此需要在并发访问时进行加锁
- 堆适用于存储大量数据或者需要动态扩展的数据结构