引用计数法(Refrence Counting)

引用计数法是最经典也是最古老的垃圾收集方法。

原理:

为每个对象配备一个整型计数器,对于一个对象A,只要有任何一个对象引用了A,则A的计数器就加1,当引用失效时,引用计数器就减1,只要对象A的引用计数器值为0,A就不可能在被使用。

问题:

  • 无法处理循环引用的问题,例如两个对象相互持有对方引用,而不存在任何第三个对象持有他们的引用,他们本该是垃圾回收的对象,但是因为存在相互引用,从而使垃圾回收器无法识别,引起内存泄露
  • 计数器要求每次引用产生和消除时,伴随一个加减法操作,对系统性能有一定影响

示意图:

存在内存泄漏及性能问题,Java虚拟机未采用此算法

标记清除法(Mark-Sweep)

标记清除法师现代垃圾回收算法的思想基础。

原理:

笔记清除算法将垃圾回收分为两个阶段:标记阶段和清除阶段。一种可行的方式是,在标记阶段,首先通过根节点,标记所有从根节点开始的可达对象,因此,未被标记的对象就是未被引用的垃圾对象。然后,在清除阶段,清除所有未被标记的对象。

问题:

标记清除算法回收后的控件时不连续的,会产生空间碎片,在对象的堆空间分配过程中,尤其是大对象的分配,不连续内存空间的工作效率要低于连续的空间。

复制算法(Copying)

原理:将内存空间分为两块,每次只使用其中一块,在垃圾回收时,将正在使用的内存中的存活对象复制到未使用的内存块中,之后,清除正在使用的内存中的所有对象,交换两个内存的角色。如果系统中垃圾对象多,需要复制的存活对象数量就会相对较少,因此,复制算法的效率是很高的,而且新的内存空间中可以保证是没有内存碎片的。

问题:

  • 复制算法的代价是将系统内存折半,一般情况下很难让人接受。
  • 对于存活对象较多的情况,效率不能保证

标价压缩法(Mark-Compact)

当内存中存活对象占比较高时,复制算法的成本很高。标记压缩算法在标记清除算法的基础上做了一些优化,标记压缩算法也是从根节点开始,对所有可达对象做一次标记,但是它并不是简单地清除未标记对象,而是将所有对象压缩到内存的一段,之后清理边界外所有的空间,避免了空间碎片的产生,又不需要浪费一半内存空间。效果相当于进行标记清除算法后再进行一次内存碎片整理。