Golang内存逃逸
堆内存(Heap):一般来讲是人为手动进行管理,手动申请、分配、释放。一般硬件内存有多大堆内存就有多大。适合不可预知大小的内存分配,分配速度较慢,而且会形成内存碎片。
栈内存(Stack):是一种拥有特殊规则的线性表数据结构。由编译器进行管理,自动申请、分配、释放。大小一般是固定的。
作者:我是一只鱼吖
链接:https://juejin.cn/post/7140864963974791175
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
在 Go 语言(Golang)中,编译器会尝试在栈上分配局部变量,因为栈上分配的速度更快,并且能够在函数返回时自动回收。但是,如果编译器发现某个变量的生命周期超出了其函数的范围,它就会将该变量分配到堆上,这个过程称为“逃逸分析”。
逃逸分析 是编译器在编译期间进行的一种分析,用来确定变量的生命周期是否超出了函数的作用域。
可以看看这个
https://juejin.cn/post/6992178559208914957
什么是内存逃逸?
逃逸值得是在函数内部创建的对象或者变量,在函数结束后,仍然被其它部分引用或者持有
对内存管理的理解
堆内存一般来说是人为手动进行管理,手动申请分配和释放的。一般硬件内存有多大,堆内存就有多大,适合不可预知大小的内存分配,分配速度较慢,而且会形成内存碎片。(在 Go 语言中,因为 Go 有 GC 自动管理,所以程序员不需要手动释放内存)
栈内存是一种有特殊规则的线性表数据结构,由编译器进行管理,自动申请,分配和释放,大小一般是固定的,它的分配速度非常快,因为只需要移动栈顶指针
内存逃逸带来的影响
当对象或者变量等一些本应在站上分配的变量,因为其生命周期超出了函数范围,不得不分配到堆上。
这时候就会引起
- 性能开销
- 堆分配比栈分配慢
- 垃圾回收也会带来开销
- 内存碎片
- 堆内存很容易产生内存碎片
- 缓存局部性
- 栈内存通常具有更好的缓存局部性,因为栈上的数据通常是连续分配的,而且生命周期短。
- 堆内存的分配是分散的,可能导致缓存未命中的问题,影响性能。
导致内存逃逸的原因
-
变量的生命周期超出了栈内存的活动范围
-
编译时不知道变量大小,因为栈内存的分配需要编译器在编译时知道变量的大小和生命周期
编译时无法确定变量大小的情况:如果变量的大小在编译时无法确定(例如动态数组、切片、映射等),编译器无法在栈上为其分配固定大小的内存。
此时,编译器会将这些变量分配到堆上,以确保程序能够正常运行。
-
Golang 的内存分片基本原则
- 指向栈上对象的指针不能被存储到堆中
- 指向栈上对象的指针不能超过该栈对象的生命周期