golang的内存逃逸

Author Avatar
evan chang 8月 30, 2023
  • 在其它设备中阅读本文章

堆内存与栈内存的区别

  • 栈内存由系统进行分配与释放,堆内存由程序自身进行申请与释放
  • 栈内存一般存放函数参数、函数返回值、局部变量、函数调用时的临时上下文,堆内存一般存放全局变量
  • 栈内存的访问速度比堆内存快
  • 每个线程分配一个栈内存,每个进程分配一个堆内存
  • 栈内存创建时,内存大小固定,越界发生stack overflow,堆内存创建时大小不固定,可随程序运行进行增加或减少
  • 栈内存是由高地址向低地址增长,堆内存是由低地址向高地址增长

go的内存管理

  • golang对内存管理是由golang自己进行处理的,程序会在启动时向系统申请一块较大的内存,然后由golang自己决定将变量分配到栈还是堆
  • 分配选择:基本原则同上面区别中所描述,不同的是对函数的引用参数的处理,如果编译器无法证明函数返回之后变量是否仍然被引用,此时就必须将该变量分配到堆内存上,然后通过垃圾回收机制进行管理,避免指针悬空。另外局部变量过大,也会被分配到堆内存,例如大切片

栈内存

  • 栈内存的分配与释放全权由操作系统决定,开发者无法控制。一般栈内存会自动创建,函数返回的时候内存会被自动释放。栈内存的分配与释放速度较快

堆内存

  • 对存有由于不确定大小,因此代价就是分配速度较慢会形成内存碎片。堆内存不能自动被编译器释放,只能通过垃圾回收器才能释放

内存逃逸

  • 把函数内的局部变量通过指针形式返回
  • 发送指针或带有指针的值到channel中
  • 在切片中存储指针或带指针的值
  • Slice的底层数组被重新分配。比如使用append向容量已满的Slice追加元素,会重新为Slice分配底层数组
  • 在interface类型上调用方法。因为interface类型调用方法都是动态调度,只有在运行的时候才能知道真正的实现

This blog is under a CC BY-NC-SA 3.0 Unported License
本文链接:https://alpherjang.github.io/2023/08/30/golang%E7%9A%84%E5%86%85%E5%AD%98%E9%80%83%E9%80%B8/