这是我参与「第五届青训营 」伴学笔记创作活动的第 5 天
一、本堂课重点内容:
- 内存管理优化
- 编译器优化
- 自动内存管理和Go内存管理机制
- 编译器优化的基本问题和思路
二、详细知识点介绍:
- 提高cpu的占用率,降低内存的使用率,减少IO的延迟
- 业务层优化:因为针对的具体问题,容易获得较大的性能收益
- 语言运行时优化:解决通用的性能问题,考虑更多的场景
- 数据驱动 依赖数据而非猜测
- 保证接口稳定的前提下改进具体的实现
- 测试用例覆盖尽可能多的场景
- 文档和隔离 通过选项控制是否开启优化 需要必要的日志输出保证可观测性
- 程序在运行时根据需求动态分配的内存:malloc()
- 自动内存管理(垃圾回收):由程序语言的运行时系统管理动态内存
- 三个任务:1、为新对象分配对象2、找到存活对象3、回收死亡对象的内存空间
- Mutator 业务线程,分配新对象,修改对象指向关系
- Collector:GC线程,找到存活对象,回收死亡对象的内存空间
- serial GC:只有一个collecter
- parallel GC:支持多个collectors同时回收的GC算法
- Concurrent GC:Mutator 和 Collector可以同时执行,但是必须感知对象指向关系的改变(三色标记法和混合写屏障
- 减少GC时间,即吞吐率
- 暂停时间 业务是否感知
- 对象被回收的条件:指针指向对象不可达的对象
- 标记根对象:静态变量、全局变量、常量、线程栈
- 标记可达对象:从跟对象出发求指针指向关系的传递闭包,找到所有可达对象
- 清理所有不可达对象:1、将存活对象复制到另外的内存空间(copying)GC 2、将死亡对象的内存标记为“可分配”(Mark-sweep GC)3、移动并整理存活对象,即原地整理对象(Mark-compaxt GC)
- 根据对象的生命周期,使用不同的标记和清理策略
- 分代假说:很多对象在分配出来后很快就不再使用了
- 针对年轻和年老的对象,指定不同的GC策略,降低整体内存管理开销。年轻代,标记清除法,老年代,标记整理法。
- 引用计数法缺点是开销较大,需要保证原子性和可见性,额外的内存空间和可能引发暂停
- Go内存分配:为对象在heap上分配内存,提前将内存分块
- mmap向操作系统申请一大块内存。将内存划分为8KB大小的mspan。再将大块继续划分成特定大小的小块用于对象分配。根据对象的大小,选择最合适的块分配。
- 对象分配时非常高频的操作:每秒分配GB级别的内存同时小对象的占比较高。
- goroutine allocation buffer(GAB),使用三个指针维护:base,end,top。将多个小对象的分配合并成一次大对象的分配。
- 问题:GAB的对象分配对象会导致内存被延迟释放。解决:采用标记复制法。
- 静态分析:不执行程序代码,推导程序的行为,分析程序的性质。
- 编译器优化:函数内联:将被调用的函数体(callee)的副本替换到调用位置()、逃逸分析(将过程间分析转化为过程内分析)
- 函数内联:将被调用的函数体(callee)的副本替换到调用位置上,同时重写代码以反映参数的绑定
- 逃逸分析:分析代码中指针的动态作用域:指针在何处可以被访问
三、实践练习例子:
- 无
四、课后个人总结:
- Go语言的内存管理和垃圾回收和Java非常相似。这堂课介绍的应该也有字节自己开发的优化项目,虽然有一定提升,但是感觉不是很明显。我感觉这方面应该是有瓶颈难以突破的。
五、引用参考:
-
无