Go 内存管理及性能优化 | 青训营笔记

101 阅读3分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 4 天

今天主要讲了Go 的内存管理及性能与编译优化,奈何本人基础浅薄,只能从自己的编码水平去理解今天的内容。

性能优化

由于项目底层结构复杂,性能优化有着针对不同层次的优化。

  • 业务层优化

针对特定场景使用合适的方案进行优化

带来的性能收益大

  • 语言运行时优化

考虑更多性能问题

解决更通用的性能问题

  • 数据支持及来源

对于性能优化不可盲目臆测,需要有理论且有数据地进行,其中有数据是最有力的支持

对于数据来源,可以使用自动化性能分析工具 pprf

软件质量

软件质量至关重要

  1. 在保证接口稳定的情况下,应该尽可能地去优化代码,改进具体实现
  2. 通过选项开启是否优化,对优化前后的版本进行隔离
  3. 文档要说清楚功能和效果,让你奶奶都能读懂的程度
  4. 需要输出必要的日志信息保证可观测性
  5. 测试用例应该覆盖尽可能多的场景

关于 SDK

SDK即Software Development Kit的缩写(译作软件开发工具包)

软件开发工具包是辅助开发某一类软件的相关文档、范例和工具的集合。

完整的SDK包含了:

  1. 接口文件和库文件
  2. 帮助文档
  3. 开发示例
  4. 辅助工具

平时我们所写的代码就是写在SDK中,可以按以上标准规范代码。

自动内存管理

为了避免手动管理内存,专注于业务实现,保证内存使用的正确性与安全性,我们通常会使用自动内存管理,即由程序运行时系统管理动态内存(即程序运行时根据需求动态分配的内存)。

GC(垃圾回收)

GC的任务是为新对象分配空间找到存活对象,回收死亡对象的内存

搬运了同期青训营“贺兰”大佬整理的相关名词:

  • Mutator:业务线程,分配新对象,修改对象指向关系
  • Collector:GC线程,找到存活对象,回收死亡对象的内存空间
  • Serial GC:只有一个collector
  • Parallel GC:支持多个collectors同时回收的GC算法
  • Concurrent GC:mutator(s) 和 collector(s) 可以同时执行

Go 内存管理

  • 内存分配之分块

提前在堆上为目标分配内存

调用系统用mmap()向操作系统申请一大块内存,例如4MB

先将内存划分成大块,例如8KB,称作mspan

再将大块划分成特定大小的小块,用于按需对象的合适大小的分配

相关名词概念:

noscan mspan:分配不包含指针的对象——GC不需要扫描

scan mspan:分配包含指针的对象——GC需要扫描

  • 内存分配之缓存

对于没有对象的mspan不会立刻释放给操作系统,而是缓存下来在需要的时候重新使用。

Balanced GC

字节跳动的优化方案

使用三个指针维护GAB(goroutine allocation buffer):base基地址, end结束地址, top当前地址

Bump pointer(指针碰撞)风格对象分配:

  • 无需和其他分配请求互斥
  • 分配动作简单高效(移动top指针)
if top + size <= end {
        addr := top
        top += size
        return addr
}

路漫漫其修远兮,吾将上下而求索