Golang内存逃逸

什么是内存逃逸?

逃逸值得是在函数内部创建的对象或者变量,在函数结束后,仍然被其它部分引用或者持有

对内存管理的理解

堆内存一般来说是人为手动进行管理,手动申请分配和释放的。一般硬件内存有多大,堆内存就有多大,适合不可预知大小的内存分配,分配速度较慢,而且会形成内存碎片。(在 Go 语言中,因为 Go 有 GC 自动管理,所以程序员不需要手动释放内存)

栈内存是一种有特殊规则的线性表数据结构,由编译器进行管理,自动申请,分配和释放,大小一般是固定的,它的分配速度非常快,因为只需要移动栈顶指针

https://blog.meowrain.cn/api/i/2025/01/27/Gst1oj1737971417379833751.avif

内存逃逸带来的影响

当对象或者变量等一些本应在站上分配的变量,因为其生命周期超出了函数范围,不得不分配到堆上。 这时候就会引起

  • 性能开销
    • 堆分配比栈分配慢
    • 垃圾回收也会带来开销
  • 内存碎片
    • 堆内存很容易产生内存碎片
  • 缓存局部性
    • 栈内存通常具有更好的缓存局部性,因为栈上的数据通常是连续分配的,而且生命周期短。
    • 堆内存的分配是分散的,可能导致缓存未命中的问题,影响性能。

导致内存逃逸的原因

  1. 变量的生命周期超出了栈内存的活动范围 https://blog.meowrain.cn/api/i/2025/01/27/sUFkIl1737971438364038419.avif

  2. 编译时不知道变量大小,因为栈内存的分配需要编译器在编译时知道变量的大小和生命周期 编译时无法确定变量大小的情况:

    如果变量的大小在编译时无法确定(例如动态数组、切片、映射等),编译器无法在栈上为其分配固定大小的内存。

    此时,编译器会将这些变量分配到堆上,以确保程序能够正常运行。

  3. Golang 的内存分片基本原则

    • 指向栈上对象的指针不能被存储到堆中
    • 指向栈上对象的指针不能超过该栈对象的生命周期

相关内容

0%