这是我参与「第五届青训营 」伴学笔记创作活动的第 4 天
今天主要讲了Go 的内存管理及性能与编译优化,奈何本人基础浅薄,只能从自己的编码水平去理解今天的内容。
性能优化
由于项目底层结构复杂,性能优化有着针对不同层次的优化。
- 业务层优化
针对特定场景使用合适的方案进行优化
带来的性能收益大
- 语言运行时优化
考虑更多性能问题
解决更通用的性能问题
- 数据支持及来源
对于性能优化不可盲目臆测,需要有理论且有数据地进行,其中有数据是最有力的支持
对于数据来源,可以使用自动化性能分析工具 pprf
软件质量
软件质量至关重要
- 在保证接口稳定的情况下,应该尽可能地去优化代码,改进具体实现
- 通过选项开启是否优化,对优化前后的版本进行隔离
- 文档要说清楚功能和效果,让你奶奶都能读懂的程度
- 需要输出必要的日志信息保证可观测性
- 测试用例应该覆盖尽可能多的场景
关于 SDK
SDK即Software Development Kit的缩写(译作软件开发工具包)
软件开发工具包是辅助开发某一类软件的相关文档、范例和工具的集合。
完整的SDK包含了:
- 接口文件和库文件
- 帮助文档
- 开发示例
- 辅助工具
平时我们所写的代码就是写在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
}
路漫漫其修远兮,吾将上下而求索