这是我参与「第五届青训营 」伴学笔记创作活动的第 5 天。这篇文章主要是针对《性能 Go 语言发行版优化与落地实践》这节课当中自动内存管理这一部分所做的笔记。
相关概念
Mutator: 业务线程,分配新对象,修改对象指向关系。
Collector: GC (垃圾回收)线程,目的是找到存活的对象、回收死亡的对象以释放内存空间。
Serial GC:只有一个 collector的 GC 算法。
Parallel GC: 支持多个 collectors 同时回收的 GC 算法。
Concurrent GC: mutator(s) 和 collector(s) 可以同时执行。
安全性(Safety):不能回收存活的对象,是自动内存管理的基本要求。
吞吐率(Throughput):1 - GC 时间/程序执行总时间
暂停时间(Pause time): stop the world (STW),判断业务是否感知。
内存开销(Space overhead): GC元数据开销。
GC 的不同策略
根据不同对象的生命周期,我们应该采取不同的合适的 GC 策略。
Copying GC:将存活对象复制到另外的内存空间
对于年轻代(经历GC次数较少)的对象,很多对象都是分配出来后很快便不再使用了。由于存活的对象很少,这屋里我们就可以采用Copying GC的策略,提高GC Throughput。
Mark—sweep GC:将死亡对象的内存标记为“可分配”
与年轻代相反,老年代对象趋向的是一直存活着,若继续使用Copying GC策略则会加剧开销,因此在这里便可以采用Mark—sweep GC减小开销。
Mark-compact GC:移动并整理存活对象
引用计数
每个对象都拥有一个与其关联的引用数目,当引用数目降为0时,该对象就会被判定为不再存活。
优点
1、在程序执行的过程中就可以执行计数操作,即内存管理的操作被平摊到了程序执行的过程中,提高效率。
2、内存管理时就不需要了解Runtime的执行过程了。
缺点
1、维护引用计数的开销过大。
2、无法回收环状结构:当数个对象围成环状相互引用时,由于各个对象引用计数都是1,无法判断对象以及死亡了。
3、回收内存时可能引发暂停。