这是我参与「第三届青训营 -后端场」笔记创作活动的的第3篇笔记。
1.自动内存管理
动态内存
自动内存管理
相关概念
Mutator: 业务线程
Collector: GC线程
Serial GC: 只有一个collector
Parallel GC: 支持多个Colletors同时回收的GC算法
Concurrent GC: mutators和collectors可以同时进行 (Collector必须感知对象指向关系的改变)
比如在GC的过程中可能会有新的引用连接上, 这时候就需要通过一些算法来感知这个变化
追踪垃圾回收
对象被回收的条件: 指针指向关系不可达的对象
标记根对象: 比如静态遍历, 全局变量, 常量和线程栈等
标记: 找到可达对象
清理: 所有不可达对象
1.标记-复制 GC
2.标记-清除 GC
3.标记-整理 GC
分代GC
老年代, 年轻代, 使用不同的分配策略和清除策略
根据对象的生命周期, 使用不同的标记和清理策略
2.go内存管理及优化
字节跳动的优化方案 Balanced GC
if top + size <= end {
addr := top
top += size
return addr
}
一个Gab对于Go内存管理来说是一个大对象
本质: 将多个小对象合并成一个大对象
问题: GAB的对象分配方式会导致内存被延迟释放
方案: 移动GAB 中存活的对象
本质: 用标记-复制算法来管理小对象
3.编译器和静态分析
4.go编译器优化
函数内联
简单理解就是把函数体内容直接插入到函数调用处,同时还要把实际参数写进去,减小函数调用的开销。
优点:
消除函数调用开销,如传递参数、保存寄存器等 将过程间分析转换为过程内分析,帮助其他优化,例如逃逸分析
缺点:
函数体变大,对于指令缓存不友好
相当于总的指令条数变多了,原来n个函数调用只有固定的一个函数那个多的指令,内联之后需要n个函数量的指令。
编译生成的Go镜像变大
综合优缺点,通过函数规模来控制是否内联,最终一般都是正向收益。
不过Golang中函数内联比较保守,还有一些语言特性(如interface和defer)限制了函数内联。为此字节推出了Beast mode,调整了Golang的内联策略降低了函数调用的开销并增加了逃逸分析的机会,编译时间约增加了10%,Go语言镜像略微增大。