GO语言进阶|青训营笔记

79 阅读2分钟

这是我参与「第三届青训营-后端场」笔记创作活动的的第2篇笔记

语言进阶-内存管理

一些概念:

  1. Mutator:业务线程,分配新对象,修改指向关系
  2. Collector:GC线程,寻找回收垃圾
  3. Serial:单个collector
  4. Parallel GC:支持多个collectors并行
  5. Concurrent GC:mutators与collectors可以同时执行,collectors须感知对象指向关系的改变
  6. Copying GC:将存活的对象复制到另外的空间
  7. Mark-sweep GC:将死亡的对象标记为可分配
  8. Mark-compact GC 移动并整理存活对象

分代GC

分代假说:很多对象分配后很快不再使用,对不同年轻、年老的对象执行不同的GC策略。

年轻代:常规的对象分配,存活对象少,可采用copying collection,GC吞吐率高

老年代,对象倾向于一直活着,反复复制开销大,采用mark-sweep collection

GO内存分块

GO为目标分配内存时,首先系统调用mmap(),申请内存,将内存划分成大块,称作msapn,将大块划分成特定大小的小块,用于对象分配。noscan/scan mspan:分配不包含/包含指针的对象,GC不需要/需要扫描。再根据对象大小选择适合的块返回。

缓存

这部分跟java不一样,每个线程M被分配一个处理器P,一次处理一个goroutine,mcache为每个goroutine分配各自的内存,mcache分配完毕,向mcentral申请有未分配块的mspan,当mspan中没有分配的对象,会被缓存在mcentral中,而不是立刻归还os。

优化

每秒GB级别的分配

优化方案:

Balanced GC:每个g绑定一大块内存1KB,goroutine allocation buffer。nonsacn类型对象分配<128B,三个指针维护GAB: base, end, top。将多个小对象的分配合并成一次大对象的分配。GAB总大小超过一个阈值,将其中存活的对象复制到其他GAB中,即cpying GC。

Beast mode

逃逸分析,函数内联拓展了函数边界,更多对象不逃逸,未逃逸的对象可以在栈上分配。类似于C的inline,go:noinline 告诉编译器不要进行内联优化。