这是我参与「第五届青训营 」笔记创作活动的第4天
1.课前预习相关重要概念
自动内存管理
-
Auto memory management: 自动内存管理
程序运行时系统自动管理内存,避免手动管理内存,使得我们可以专注于实现业务逻辑
-
Grabage collction: 垃圾回收(GC)
垃圾回收是一种自动管理内存的方式,支持GC的语言无需手动管理内存,程序后台自动判断对象是否存活并回收其内存空间,使开发人员从内存管理上解脱出来
- Mutator: 业务线程
- Collector: GC 线程
- Concurrent GC: 并发 GC
- Parallel GC: 并行 GC
-
Tracing garbage collection: 追踪垃圾回收
- Copying GC: 复制对象 GC
- Mark-sweep GC: 标记-清理 GC
- Mark-compact GC: 标记-压缩 GC
-
Reference counting: 引用计数
一种实现GC的算法
-
Generational GC: 分代 GC
- Young generation: 年轻代
- Old generation: 老年代
Go 内存管理及优化
- TCMalloc
mmap()系统调用
- scan object 和 noscan object
- mspan, mcache, mentral
- Bump-pointer object allocation: 指针碰撞风格的对象分配
编译器和静态分析
- 词法分析
- 语法分析
- 语义分析
- Intermediate representation (IR) 中间表示
- 代码优化
- 代码生成
- Control flow: 控制流
- Data flow: 数据流
- Intra-procedural analysis 过程内分析
- Inter-procedural analysis: 过程间分析
Go 编译器优化
- Function inlining: 函数内联
- Escape analysis: 逃逸分析
上节课回顾
问题:pprof采样原理?
————————————————————————————课程开始分割线
Go语言优化
什么是性能优化?
为什么要做性能优化?
性能优化的层面
- 业务代码
- SDK
- 基础库
- 语言运行时
- OS
主要有两种优化:业务层优化 语言运行时优化
内存管理优化
编译器优化
Go SDK
1.自动内存管理
GC可以保证内存使用的正确性和安全性
GC的三个任务
1.为对象分配空间
2.找到存活对象
3.回收死亡对象的内存
三种GC的执行方式,其中前两种都需要暂停业务线程
第三种可以让业务线程和GC线程同时执行
Concurrent GC也存在问题:
它必须要感知到对象指向关系的改变,否则就会出错
如图,b对象是在GC过程中新加入的对象,GC必须要将它也标记为存活的,否则就会出错
评价GC算法
两种常见的GC技术
1.追踪垃圾回收
对象被回收的条件,指针指向关系不可达的对象
流程:
标记根对象
标记:所有可达对象
清理:所有不 可达对象
一些清理策略(如何选择?需要根据对象的生命周期,使用不同的标记和清理策略)
Copying GC: 将当前区域存活的对象复制到另外的内存空间去,这样,原来的区域就可以被清空了
Mark-sweep GC: 将死亡对象的内存空间用一个free list管理起来,下次分配内存时,直接通过free list找一个块即可
Compact GC:将存活的对象拷贝到内存最开始的地方(原地整理对象),它和copying GC很像,只不过拷贝到的地方不一样
2.引用计数
每个对象都有一个与之关联的引用数字
对象存活条件:引用数字大于0
优点:
1.内存管理的操作被平摊到程序执行过程中
2.内存管理不需要了解runtime的实现细节
缺点:
2.Go 内存管理及优化
2.1 内存分配——分块
目标:为对象在heap上分配内存
2.3 字节的优化方案——Balanced GC
每个g都绑定一大块内存(1 KB),称作goroutine allocation buffer(GAB)
GAB用于noscan类型的小对象分配:<128B
使用三个指针维护这个g
分配的处理只是移动指针,非常高效
GAB本质上就是将多个小对象的分配合并成一个大对象的分配
3.编译器和静态分析
经典编译器结构
3.2 静态分析
不执行代码,推导程序的行为
4.Go 编译器优化
函数内联、逃逸分析
4.1 函数内联
将要调用的函数直接拷贝到对应的位置上,相当于不用调用了?直接用
性能优化非常明显
4.2 逃逸分析
分析代码中指针的动态作用域;指针在何处可以被访问
具体思路