Go语言内存优化与落地实践-2|青训营笔记

108 阅读2分钟

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

分代GC(Generational GC)

  • 分代假说(Generational hypothesis):most objects die young

  • Intuition:很多对象在分配出来后很快就不再使用了

  • 每个对象都有年龄:经历过GC的次数

  • 目的:针对年轻和老年的对象,制定不同的GC策略,降低整体内存管理的开销

  • 不同年龄的对象处于heap的不同区域

  • 年轻代(Young generation)

    • 常规的对象分配
    • 由于存活对象很少,可以采用 copying collection GC吞吐率很高
  • 老年代(Old generation)

    • 对象趋向于一直活着,反复复制开销较大

    • 可以采用 mark-sweep collection

image.png

image.png

引用计数

  • 每个对象都有一个与之关联的引用数目
  • 对象存活的条件:当且仅当引用数大于0
  • 优点
    • 内存管理的操作被平摊到程序执行过程中
    • 内存管理不需要了解runtime 的实现细节:C++智能指针(smart pointer)
  • 缺点
    • 维护引用计数的开销较大:通过原子操作保证对引用计数操作的原子性可见性

    • 无法回收环形数据结构-weak reference

    • 内存开销:每个对象都引入的额外内存空间存储引用数目

    • 回收内存时依然可能引发暂停

image.png

Go内存分配一分块

  • 目标:为对象在heap上分配内存
  • 提前将内存分块
    • 调用系统调用map()向OS申请一大块内存,例如4MB
    • 先将内存划分成大块,例如8 KB,称作mspan
    • 再将大块继续划分成特定大小的小块,用于对象分配
    • noscan mspan:分配不包含指针的对象-GC不需要扫描
    • scan ms pan:分配包含指针的对象-GC需要扫描
  • 对象分配:根据对象的大小,选择最合适的块返回

image.png

Go内存分配一缓存

  • TCMalloc:thread caching
  • 每个p包含一个mcache用于快速分配,用于为绑定于p上的g分配对象
  • mcache管理一组mspan
  • 当mcache中的mspan分配完毕,向mcentral申请带有未分配块的mspan
  • 当mspan中没有分配的对象,mspan会被缓存在mcentral 中,而不是立刻释放并归还给OS

image.png