1. 对象创建
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 三色标记法+混合写屏障
- GC 开始时将栈上可达对象全部标记为黑色(不需要二次扫描,无需 STW)
- GC 期间,任何栈上创建的新对象均为黑色
- 被删除引用的对象标记为灰色
- 被添加引用的对象标记为灰色
2.3 GC触发时机
- 堆内存的分配达到控制器计算的触发堆大小,初始大小环境变量 GOGC,之后堆内存达到上一次垃圾收集的 2 倍时才会触发 GC。
- 如果一定时间内没有触发,就会触发新的循环,默认为2分钟。
3. 内存优化技巧
- 使用strings.Builder
- 函数中尽可能使用值而不是指针(逃逸分析)
- map存值而不是指针(逃逸分析)
- 使用sunc.Pool优化内存
- 使用struct{}优化内存(空struct{}不占内存空间)
- 使用atomic优化
- 使用不带缓冲区的channel(避免逃逸分析)