这是我参与「第五届青训营」笔记创作活动的第5天。
学习内容
今天学习了go的内存管理优化以及编译器优化。
性能优化
提升软件系统的处理能力,减少不必要的消耗,充分发掘计算机算力。
- 提升用户体验;
- 资源高效利用,降低成本。
软件质量至关重要
- 保证接口稳定
- 测试用例:覆盖尽可能多的场景,方便回归
- 写文档
- 隔离:通过选项控制优化是否开启
- 客观性:必要的日志输出
自动内存管理
自动内存管理(垃圾回收),由程序语言的运行时系统管理动态内存,保证内存使用的正确性、安全性。
三个任务
- 为新对象分配空间
- 找到存活对象
- 回收死亡对象的内存空间
一些概念
- Mutator:业务线程,分配新对象,修改对象指向关系
- Collector:GC线程,找到存活对象,回收死亡对象的内存空间
- Serial GC:只有一个collector
- Parallel GC:支持多个collectors同时回收的GC算法
- Concurrent GC:mutator和collector可以同时执行
评价GC算法
- 安全性:不能回收存活对象
- 吞吐率:花在GC上的时间
- 暂停时间:业务是否感知
- 内存开销:GC元数据开销
追踪垃圾回收
对象回收条件:指针指向关系不可达的对象
三个步骤:
- 标记根对象,包括静态变量、全局变量、常量和线程栈等;
- 标记可达对象,从根对象出发,找到所有可达对象;
- 清理所有不可达对象:Coping GC、Mark-sweep GC和Mark-compact GC。
引用计数
每个对象都有一个与之关联的引用数目,当且仅当引用数大于0时对象存活。
Go的内存管理及优化
为对象在heap上分配内存
在Go中会提前将内存分块:
- 调用系统调用mmap()向OS申请一大块内存;
- 先将内存划分为大块,称为mspan;
- 再将大块继续划分为特定大小的小块用于对象分配;
- noscan mspan:分配不包含指针的对象;
- scan mspan:分配包含指针的对象。
根据对象大小,选择合适的块返回。
缓存:TCMalloc
Go内存管理优化
Balanced GC:
- 每个g都绑定一大块内存(1KB)GAB
- GAB用于noscan类型的小对象分配(<128 B)
- 使用三个指针维护GAB,base、end和top
- Bump pointer(指针碰撞)风格对象分配:无信仰和其他分配请求互斥;分配动作简单高效。
以上针对一个小对象的内存分配,将多个小对象的分配合成一次大对象的分配。
问题:导致内存被释放延迟
方案:移动GAB中存活的小对象
编译器优化
编译器
静态分析
不执行程序代码,推导程序的行为,分析程序的性质。
- 控制流:程序执行的流程
- 数据流:数据在控制流上的传递
- 过程内分析
- 过程间分析
Go的编译器优化
函数内联
将被调用函数的函数体的副本替换到调用位置上,同时重写代码以反映参数的绑定。
逃逸分析
分析代码中指针的动态作用域:指针在何处可以被访问。