这是我参与「第三届青训营 -后端场」笔记创作活动的第4篇笔记
做性能优化可以从那些方面出发
需要工具辅助,不能盲目猜测
目录
1.自动内存管理
背景
相关概念
- Mutator:业务线程,分配新对象,修改对象指向关系
- Collector:GC线程,找到存活的对象,回收死亡对象的内存空间
- GC算法的分类
- Serial GC:只有一个collector,有暂停
- Parallel GC:支持多个collectors同时回收的GC算法,有暂停
- Concurrent GC:mutators和collectors可以同时执行,不用暂停
Concurrent GC的一些挑战:Collectors必须感知到对象只想关系的改变
评价GC算法(四个方面)
- 希望花在GC上面的时间越少越好
- 暂停时间越短越好
- 内存开销也是越小越好
推荐书:
两种常见的GC技术
- 追踪垃圾回收(Tracing garbage collection)
- 引用计数(Reference counting)
1.2追踪垃圾回收
- 对象被回收的条件:指针指向关系不可达的对象
分为以下3个步骤
- 标记根对象
- 先将静态变量、全局变量、常量、线程栈等标记为存活的,因为后面还有可能会用到
- 标记:找到可达对象
- 从根对象出发,找到所有可达的对象
- 也就是求指针指向关系的传递闭包
- 清理:所有不可达的对象
- 清理的时候也会有一些不同的清理策略
- 将存活的对象复制到另外的内存空间(Copying GC)【下面这张图片,左边灰色的部分就是存活的对象,将存活的对象复制到右边的区域】
- 将死亡对象的内存标记为"可分配"(Mark-sweep GC)【将死亡空间用用一个free List管理起来】
- 移动并整理存活对象(Mark-compact GC)【没有额外的内存空间了,原地整理对象】
- 将存活的对象复制到另外的内存空间(Copying GC)【下面这张图片,左边灰色的部分就是存活的对象,将存活的对象复制到右边的区域】
- 清理的时候也会有一些不同的清理策略
我们需要根据对象的生命周期,使用不同的标记和清理策略
1.3分代GC(Generational GC)
- 分代假说
1.4引用计数
第二种常见的内存管理机制
- 每个对象都有一个与之关联的引用数目
- 箭头指向这个对象的个数就是引用的数目
- 存活条件:引用数大于0
- 优点
- 内存管理的操作被平摊到程序执行过程中(程序一边执行,内存管理的操作也在执行)
- 内存管理不需要里了解runtime的实现细节,比如C++的智能指针
- 缺点
回收环形数据结构可以使用weak reference
总结
内存管理的概念和评价方法,2种常见的自动内存管理的算法,常见的管理方法:分代GC,为不同声明周期的对象指定不同的回收机制
2.Go内存管理及优化
2.1Go内存分配-分块
- 目标:为对象在heap上分配内存
- 怎么做:提前将内存分块
- 对象分配:过根据对象的大小,选择最合适的块返回
2.1Go内存分配-缓存
2.2Go内存管理优化
2.3优化方案:Balanced GC
针对针对对象分配的优化方案
针对小对象
针对问题的解决方案:用copying GC的算法管理小对象
2.3Balance GC - 性能收益
总结
3.编译器和静态分析
3.1编译器的结构
3.2静态分析
编译器后端优化一般来说都要用到一个工具/技术:静态
3.3过程内分析和过程间分析
过程间分析很复杂
总结
4. Go编译器优化
背景
4.1函数内联(Inlining)
右边那个图片,用编译器的一个选项,强制要求不inline
- 缺点
4.2 Beast Mode
4.2逃逸分析
- 概念:分析代码中指针的动态作用域,也就是指针在何处可以被访问到
- 具体怎么做?
- Beast mode具体对逃逸分析做了哪些优化?
GC是在堆上进行操作
总结
参考文献