Go内存管理与性能优化

626 阅读2分钟

1. 对象创建

image.png

Go内存分配的最小单元是span,span为操作系统中内存块的整数倍。内存管理是针对g而言的,毕竟协程的运行信息是g管理的,当创建的对象大于32kb时,g会直接在mheap中创建对象,小于32 kb时,g会先请求p中mcache中包括且最接近的span,如果mcache中没有,会向mcentral请求,如果mcentral也用完了,会向mheap请求新建。

另外,g的栈很小(2kb),并且能动态增长。

2. 垃圾回收

2.1 垃圾回收过程

  • 进行 STW(stop the worl 即暂停程序业务逻辑),然后从 main 函数开始找到不可达的内存占用和可达的内存占用

  • 开始标记,程序找出可达内存占用并做标记

  • 标记结束清除未标记的内存占用

  • 结束 STW 停止暂停,让程序继续运行,循环该过程直到 main 生命周期结束

2.2 三色标记法+混合写屏障

  1. GC 开始时将栈上可达对象全部标记为黑色(不需要二次扫描,无需 STW)
  2. GC 期间,任何栈上创建的新对象均为黑色
  3. 被删除引用的对象标记为灰色
  4. 被添加引用的对象标记为灰色

2.3 GC触发时机

  • 堆内存的分配达到控制器计算的触发堆大小,初始大小环境变量 GOGC,之后堆内存达到上一次垃圾收集的 2 倍时才会触发 GC。
  • 如果一定时间内没有触发,就会触发新的循环,默认为2分钟。

3. 内存优化技巧

  • 使用strings.Builder
  • 函数中尽可能使用值而不是指针(逃逸分析)
  • map存值而不是指针(逃逸分析)
  • 使用sunc.Pool优化内存
  • 使用struct{}优化内存(空struct{}不占内存空间)
  • 使用atomic优化
  • 使用不带缓冲区的channel(避免逃逸分析)