Golang内存逃逸
目录
什么是内存逃逸?
逃逸值得是在函数内部创建的对象或者变量,在函数结束后,仍然被其它部分引用或者持有
对内存管理的理解
堆内存一般来说是人为手动进行管理,手动申请分配和释放的。一般硬件内存有多大,堆内存就有多大,适合不可预知大小的内存分配,分配速度较慢,而且会形成内存碎片。(在 Go 语言中,因为 Go 有 GC 自动管理,所以程序员不需要手动释放内存)
栈内存是一种有特殊规则的线性表数据结构,由编译器进行管理,自动申请,分配和释放,大小一般是固定的,它的分配速度非常快,因为只需要移动栈顶指针
内存逃逸带来的影响
当对象或者变量等一些本应在站上分配的变量,因为其生命周期超出了函数范围,不得不分配到堆上。 这时候就会引起
- 性能开销
- 堆分配比栈分配慢
- 垃圾回收也会带来开销
- 内存碎片
- 堆内存很容易产生内存碎片
- 缓存局部性
- 栈内存通常具有更好的缓存局部性,因为栈上的数据通常是连续分配的,而且生命周期短。
- 堆内存的分配是分散的,可能导致缓存未命中的问题,影响性能。
导致内存逃逸的原因
-
变量的生命周期超出了栈内存的活动范围
-
编译时不知道变量大小,因为栈内存的分配需要编译器在编译时知道变量的大小和生命周期 编译时无法确定变量大小的情况:
如果变量的大小在编译时无法确定(例如动态数组、切片、映射等),编译器无法在栈上为其分配固定大小的内存。
此时,编译器会将这些变量分配到堆上,以确保程序能够正常运行。
-
Golang 的内存分片基本原则
- 指向栈上对象的指针不能被存储到堆中
- 指向栈上对象的指针不能超过该栈对象的生命周期