这是我参与「第五届青训营 」伴学笔记创作活动的第 5 天。
·性能优化是什么
提升软件系统处理能力,减少不必要的消耗,充分发掘计算机算力
·为什么要做性能优化
用户体验
资源高效利用
性能优化的层面
业务代码
SDK
基础库
语言运行时
OS
·业务层优化,针对特定场景,容易获得较大性能收益
·语言运行时优化,解决更通用的性能问题,考虑更多场景,Tradeoffs
·数据驱动,工具(pprof),依靠数据而非猜测,首先优化最大瓶颈
1.1 自动内存管理
·动态内存:malloc()
·自动内存管理(垃圾回收)
·三个任务:
·为新对象分配空间
·找到存活对象
·回收死亡对象的内存空间
·Mutator:业务县城,分配新对象,修改对象指向关系
·Collector:GC线程,找到存活对象,回收死亡对象的内存空间
·Serial GC:只有一个collector
·Parallel GC:支持多个collectors同时回收的GC算法
·Concurrent GC:mutator(s)和collecotr(s)可以同时执行
·Collectors必须感知对象指向关系的改变!
·评价GC算法
··安全性(Safety)
··吞吐率(Throughput)
··暂停时间(Pause time):stop the world(STW)业务是否感知
··内存开销(Space overhead)GC原数据开销
·追踪垃圾回收(Tracing garbage collection)
·引用计数(Reference counting)
1.2 追踪垃圾回收
·对象被回收的条件:指针指向关系不可达的对象
·标记根对象:静态变量、全局变量、常量、线程栈等
·标记:找到可达对象:从根对象出发,找到所有可达对象
·清理:所有不可达对象
··将存货对象复制到另外的内存空间(Copying GC)
··将死亡对象的内存标记为“可分配”(Mark-sweep GC)
··移动并整理存活对象(Mark-compact GC)
1.3 分代GC(Generational GC)
·分代驾说(Generational hypothesis):most objects die young
·Intuition:很多对象在分配出来很快就不再使用了
·每个对象都有年龄:经过GC的次数
·目的:针对年轻和老年的对象,指定不同的GC策略,降低整体内存管理的开销
·不同年龄的对象处于heap的不同区域
·年轻代(Young generation)
··常规的对象分配
··由于存活对象很少,可以采用copying collection
·老年代(Old generation)
··对象趋向于一只活着,反复复制开销较大
··可以采用mark-sweep collection
1.4 引用计数
·每个对象都有一个与之关联的引用数目
·对象存活条件:当且仅当引用数大于0
·优点
··内存管理的操作被平摊到程序执行过程中
··内存管理不需要了解runtime的实现细节:C++智能指针(smart pointer)
·缺点
··维护引用计数的开销较大:通过原子操作保证引用计数操作的原子性和可见性
··无法回收环形数据结构——weak reference
··内存开销:每个对象都引入的额外内存空间存储引用数目
··回收内存时依然可能引发暂停
2. Go内存管理和分配
2.1 Go内存分配——分块
·目标:为对象在heap上分配内存
·提前将内存分块
··调用系统调用mmap()向OS申请一大块内存,例如4MB
··现将内存划分成大块,例如8KB,称作mspan
··再将大块继续划分成特定大小的小块,用于对象分配
··noscan mspan:分配不包含指针的对象——GC不需要扫描
··scan mspan:分配包含指针的对象——GC需要扫描
·对象分配:根据对象大小,选择最合适的块返回
2.1 Go内存分配——缓存
·TCMalloc:thread caching
2.2 Go内存管理优化
2.3 Balanced GC
本质:将多个小对象分配合并成一个一次大对象的分配
问题:GAB的对象分配方式会导致内存被延迟释放