内存垃圾回收| 青训营笔记

67 阅读2分钟

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

今天讲了编程语言中常用的几种 GC 方案

  1. 追踪垃圾回收
  • 对象回收条件:指针指向关系不可达
  • 标记根对象
    • 静态变量、全局变量、常量、线程栈等
  • 标记:找到可达对象
  • 清理:所有不可达对象
    • 将存活对象复制到另外的内存空间(Copying GC)
    • 将死亡对象的内存标记为“可分配"(Mark-sweep GC)
    • 移动并整理存活对象(Mark-compact GC)
  • 根据对象的生命周期。使用不同的标记和清理策略
  1. 分代 GC (Generational GC)

比较容易联想到 JVM 中的 GC 机制

  • 分代假说(Generational hypothesis): most objects die young

  • Intuition:很多对象在分配出来后很快就不再使用了

  • 每个对象都有年龄:经历过GC的次数

  • 目的:对年轻和老年的对象,制定不同的GC策略,降低整体内存管理的开销

  • 不同年龄的对象处于heap的不同区域

    • 年轻代 (Young generation)
    • 常规的对象分配
    • 由于存活对象很少,可以采用copying collection(指拷贝到连续内存,减少内存碎片,方便统一管理)
    • GC吞吐率很高
  • 老年代(Old generation)

    • 对象趋向于一直活着,反复复制开销较大
    • 可以采用 mark-sweep collection
  1. 引用计数

    • 参考 C++ 的智能指针
  2. Go 的三色标记算法

Go从1.5版本实现了基于三色标记清除的并发垃圾收集器,能在不暂停程序的情况下即可完成对象的可达性分析,算法将程序中的对象分成白色、黑色和灰色三类:

  • 白色对象 - 潜在垃圾,表示还未搜索到的对象,其内存可能会被垃圾收集器回收;
  • 黑色对象 - 活跃对象,表示搜索完成的对象,包括不存在任何引用外部指针的对象以及从根对象可达的对象
  • 灰色对象 - 活跃对象,表示正在搜索还未搜索完的对象,因为存在指向白色对象的外部指针,垃圾收集器会扫描这些对象的子对象;

实现步骤:

  • 全部对象初始标记为白色
  • 从 gc root 出发,将可达对象标记为灰色,放入处理队列
  • 每次从队列中取一个灰色对象标记为黑色,并把该对象的引用对象标记为灰色,放入处理队列
  • 重复标记直到灰色队列为空
  • 清除白色的垃圾对象