GC|青训营笔记

63 阅读2分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 8 天

今天复习整理之前内存管理的部分课程

Mutator: 业务线程,分配新对象,修改对象指向关系

Collector: GC线程,找到存活对象,回收死亡对象的内存空间

 

Go Runtime

 

Serial GC: 只有一个 collector

Parallel GC: 并行 GC,支持多个 collectors 同时回收的GC算法

Concurrent GC: 并发 GC,支持 mutator(s)和collector(s)同时执行的GC算法,要求collectors必须感知对象指向关系的改变(即回收的同时程序还在运行,产生的新对象也要标记为相应的存活)

评价GC算法

安全性:不能回收存活的对象,基本要求

吞吐率(Throughput): 1-GC时间/程序总时间,即花在GC上的时间

暂停时间:stop the world (STW)业务是否感知

内存开销:GC元数据开销

追踪垃圾回收

对象被回收的条件:指针指向关系不可达的对象

标记根对象:静态变置、全局变量、常量、线程栈等

标记:找到可达对象,从根对象出发找到所有可达对象

清理:根据对象的生命周期,使用不同的标记和清理策略

将存活对象复制到另外的内存空间(Copying GC)

将死亡对象的内存标记为"可分配"(Mark-sweep GC)(类似c++)

移动并整理存活对象(Mark-compact GQ)(和coping gc类似,只不过是用同一个空间操作)

分代GC

对象的年龄:经历GC的次数

对年轻和老年对象,指定不同的GC策略,降低开销

年轻代:存活的少,可以采用coping gc

老年代:对象一直存活的多,复制开销大,可以采用mark-sweep gc

引用计数

优点:内存操作平铺到程序执行过程中,不需要复杂的机制,专注计数即可

缺点:维护引用计数开销大(要保证计数操作是原子操作),不好回收环形结构(引用计数都为1),计数本身占内存,回收复杂结构的引用计数时可能引发暂停