这是我参与「第五届青训营 」伴学笔记创作活动的第 4 天
本文是对于掘金课程的课程笔记,针对课程内容的一些重难点、本人在学习Go语言内存管理进行的简单记录。本次课程内容偏向于理论分析,因此没有进行相关实践分析
一、本堂课的重点内容
- 自动内存管理
- Go内存管理及优化
- 编译器和静态分析
- Go编译器优化
二、详细知识点介绍
性能优化
性能优化是什么?
提升软件系统处理能力,减少不必要消耗,降低成本,发掘计算机算力
为什么要性能优化?
提升用户体验
资源高效利用,降低成本,提高效率
性能优化的几个层面:
业务层优化:优势在于可以针对特定场景,具体问题具体优化,可以获得较大的性能收益
语言运行时优化:可以解决更加通用的问题,但是需要考虑更多的场景
数据驱动:在进行优化时是以数据为驱动的,我们可以使用前面学到的pprof工具进行自动化的性能分析,在优化时需要注意首先优化最大性能瓶颈
自动内存管理
- 动态内存
- 自动内存管理(垃圾回收机制)
- 三个任务:为新对象分配空间;找到存活对象;回收死亡对象的内存空间
- 内存管理相关概念
Mutator:业务线程,分配新对象
Collector:GC线程,找到存活对象,回收死亡对象的内存空间
Serial GC:只有一个collector
Parallel GC:支持多个collecotrs同时回收的GC算法
Concurrent GC:mutator 和 collecotr可以同时执行
评价GC算法的几个指标: 安全性(基本要求);吞吐率(GC用时);暂停时间(业务是否感知);内存开销(GC元数据开销)
追踪垃圾回收
- 对象被回收条件:关系不可达
- 标记根对象
- 标记:找到可达对象
- 清理:不可达对象
分代GC
- 年轻代:常规对象分配;由于存活对象少,采用copying colleciton;GC吞吐率高
- 老年代:趋向于一直活着,复制开销大,可以采用mark-sweep collection
Go内存分配
- 分块:为对象在heap上分配内存,提前将内存分块,然后根据对象的大小,选择最适合的块返回
- 缓存:快速分配,每个p包含一个mcache用于快速分配,mcache管理一组mspan,分配完毕后向mcentral申请,如果mspan没有分配对象,mspan缓存在mcentral中而不是立即释放
Go内存管理优化
使用Balanced GC
每个g都绑定一大块内存,成为GAB,用于noscan类型小对象分配,使用三个指针(base,end,top)进行维护,使用Bump pointer风格对象分配
编译器和静态分析
- 前端(分析部分):词法分析,语法分析,语义分析,中间代码生成
- 后端(综合部分):代码优化,代码生成
静态分析:
- 静态分析:不执行程序代码,推导程序行为,分析程序性质
- 控制流:程序执行流程
- 数据流:数据在控制流上的传递
- 过程内分析:仅在函数内部分析
- 过程间分析:考虑函数调用的参数传递和返回值的数据流和控制流
Go编译器优化
- 函数内联:将调用函数的函数体的副本替换到调用位置上,重写代码以反映参数绑定,将过程间分析转为过程内分析
- Beast Mode:调整函数内联策略
三、课后个人总结
学习Go语言的内存管理让我联想到了Java的内存分配,尤其是GC部分,有许多相通之处,例如年轻代与老年代的划分;引用计数机制;垃圾回收的算法等等。将各类语言的各种特性比较分类,也是学习新编程语言的好方法。