常见的GC算法

垃圾收集(Garbage Collection) 通常被称为"GC",常见的 GC 算法有 : 引用计数法、标记清除法、三色标记法、分代收集法。

引用计数法

引用计数法为每个对象维护一个整型的值,用于记录当前对象被引用的数量,当对象被引用时,此值+1,取消引用时,此值 -1。当计数器为0时,销毁对象。

优点

  • 回收垃圾速度快

  • 最大暂停时间短

    最大暂停时间 : 因执行 GC 而暂停执行程序的最长时间

缺点

  • 不能解决循环引用的问题,A对象引用了B对象,B对象也引用了A对象时。A与B的引用计数器永远不为0,永远不可以被回收。

  • 引用计数操作增加了内存与CPU消耗。

标记清除法

标记清除法分为两步:标记与清除

标记:从根节点开始,递归遍历所有对象,将能遍历到的对象打上标识。 清除:再次遍历堆,未标记的对象加入到空闲链表中,标记的对象则去除标记。

优点

  • 算法实现简单
  • 对象不被移动

缺点

  • 最大暂停时间太长
  • 清除后会产生大量内存碎片

三色标记法

三色标记法是对标记清除法的改进。是一种并行垃圾回收

过程:

  • 初始化,所有对象都是白色
  • 从根遍历(非递归),所有可达对象标记为灰色
  • 从灰色对象队列中取出对象,将其引用的对象标记为灰色,并将自己标记为黑色
  • 重复第三步,直到灰色队列为空,此时白色对象即为孤儿对象,进行回收

分代收集算法

分代GC将内存空间按”代(Generation)”分为几个部分(通常是两代,即Young Generation和Old Generation),并尽可能频繁地在年轻的一代执行GC,当年轻一代的内存空间不够时,将可达对象全部移到上一代,此时年轻代的内存空间为空闲空间,可用于分配新对象,这样更快并且通常也更有效率。当老一代GC不够用时,才执行全量GC。

通常大部分语言的运行时都会混合多种GC算法,比如Erlang的GC( 参考: 深入了解Erlang 垃圾回收机制以及其重要性 )就混合了分代GC和引用计数,在进程堆内使用分代GC,对全局数据使用引用计数(即时释放内存)。