OS层面

栈内存与堆内存的区别

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

基础信息

  • Golang是自己管理内存,不依赖操作系统,即向操作系统申请一块较大内存,然后自己决定将变量分配到栈空间或对空间
  • 分配选择:基本同上面的分配原则,但对于函数的引用参数会有一些特殊。如果编译器无法证明函数返回之后变量是否仍然被引用,此时就必须在堆空间分配该变量,随后采用垃圾回收机制管理,而从避免指针悬空。此外,如果局部变量过大,也会选择分配在堆空间
  • 总结:最终的分配空间在于编译器的选择,编译器分析变量的生存周期的过程就叫做逃逸分析

栈内存

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

堆内存

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

内存逃逸

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

优化

sync.Pool