这是我参与「第五届青训营 」伴学笔记创作活动的第 5 天
学习内存管理优化和编译器优化
隔离:通过配置选项控制是否开启优化 可观测:必要的日至输出 文档:做了什么,没做什么,达到什么效果。这样用户知道是否要开启优化
自动内存管理
- concurrently
- mutator thread:业务线程(比如 goroutine)
- Collector: GC 线程
- serial GC 只有一个 collector
- Concurrent GC: 并发 GC (nutator 和 collector 可以同时执行)
- Parallel GC: 并行 GC(多个 collector, 但 mutator 和 collector 不同时执行)
- collector 必须感知对象指向关系的改变,否则就会出错
暂停就是 StopTheWorld
并发:一个cpu 轮流切换多个线程 并行:多个 cpu 同时执行多个线程
GC 算法
评价 GC 算法
- 安全性
- 吞吐率
- 暂停时间
- 内存开销 推荐书:《the garbage collection handbook》
介绍 2 种垃圾回收算法:
追踪垃圾回收
回收条件:不可达的对象 清理方式:
- copying GC
- mark-sweep GC
- mark-compact GC
如何选择策略:根据对象生命周期,选择不同的标记和清理策略
分代 GC
分代假说:很多 young 刚分配就结束生命周期 根据对象的年龄,放在 heap 不同区域,制定不同 GC 策略
- 年轻代可使用 copying GC
- 老年代可使用 mark-sweep GC
引用计数
GCROOT 优点:
- 内存管理操作被分摊到程序执行过程中
- 不需要了解 runtime 的实现细节(比如 C++智能指针) 缺点:
- 维护计数开销大:原子操作计数
- 无法回收环形数据结构 weak reference
- 内存开销:额外空间存储引用计数
- 回收内存时可能引发暂停(回首大数据结构时,需要多时间,所以会引起暂停)
内存分配
分块
nonscan mspan:分配不包含指针对象,GC 不用扫描 scan mspan:分配包含指针对象,GC 需要扫描
缓存
TCMalloc
优化
小对象多 分配路径过长 根据以上 2 个问题开发 Balance GC
Balance GC
本质:多个小对象分配,合并成一次大对象分配 问题:GAB 的分配方式导致内存延迟释放
- 解决方法:copying GC 算法,复制到另外 GAB 中
编译器优化
静态分析
不执行代码 控制流 control flow 数据流 data flow
- 过程内分析:仅在函数内
- 过程间分析:考虑函数调用时参数传递和返回值
函数内联
将过程间分析转换成过程内分析 缺点:
- 函数体变大,instruction cache (icache) 不友好。会频繁 icache miss
- Go 镜像变大
Beast Mode: go 语言特性interface、defer 等限制了函数内联 beast mode:
- 调整内联策略,使更多函数被内联。
- 增加了其他优化的机会:逃逸分析
逃逸分析
分析代码中指针的动态作用域 函数内联扩展了函数边界,更多对象不逃逸。这样未逃逸对象可以在栈上分配