从如何判定对象消亡的角度出发,垃圾回收算法可以划分为:“引用计数式垃圾回收”和“追踪式垃圾收集”两大类。
我们目前所知的垃圾回收算法比如:标记-清除、标记-整理、标记-复制算法都属于追踪式垃圾收集。
我们目前的的垃圾收集器,大多都遵循了“分代收集”的理论进行设计。
“分代收集”建立在两个分代假说之上:
- 弱分代假说:绝代多数对象都是朝生夕灭的。
- 强分代假说:熬过越多次垃圾收集过程的对象就越难以消亡。
由这两个假说共同奠定了多款垃圾收集器的设计原则:垃圾收集器将Java堆划分出不同区域,然后将回收对象的年龄依据其年龄(年龄即对象熬过垃圾收集过程的次数)分配到不同区域中存储。
标记-清除算法(Mark-Sweep)
该算法分为“标记”和“清除”两个阶段:首先标记出所需要回收的对象,在标记完成后,统一回收掉所有被标记的对象。(标记的过程就是判断对象是否属于垃圾)。
- 缺点:
- 执行效率不稳定,标记和清除两个过程过程的执行效率都会随着对象数量增长而降低。
- 内存空间碎片化,空间碎片会导致以后在程序运行过程中需要分配较大对象的时候无法找到足够的连续内存碎片而不得不提前触发另一次垃圾收集动作。
标记-复制算法(复制算法)
该算法是为了解决标记清除算法面对大量可回收对象执行效率低的问题。该算法将内存区域按照容量划分为大小相等的两个区域,每次只使用其中的一块。当这一块的内存用完了,就将存活的对象复制到另一块上面,然后将已使用的内存空间一次清理掉。
缺点:会产生大量的内存之间复制的开销。浪费空间。
所以该算法多用于新生代。
标记-整理
标记过程仍然与上述两个算法相同,但后续步骤是让所有存活的对象都行内存空间的一端移动,然后直接清理到边界以外的内存。
优点:避免标记扫描的碎片问题;避免停止复制的空间问题。
缺点:会暂停用户线程(STW)