1、常见的垃圾回收算法
1.1 引用计数
原理:只要对象之间互相有引用,也就是,只要对象被引用了,GC 就不进行垃圾回收
缺点:
- 每次对对象赋值时要维护引用计数器,且计数器本身也有一定的消耗
- 比较难处理循环引用
JVM 的实现一般不采用这种方式。
1.2 复制
年轻代中使用的是Minor GC,这种 GC 算法采用的是复制算法。
原理:将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。如下图:从根集合(GC Root)开始,通过 Tracing 从 From 中找到存活对象,拷贝到 To 中,然后 From 和 To 交换身份,下次内存分配从 To 开始。
优点:
- 没有标记和清除的过程,效率高
- 内存在分配时不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可
缺点:
- 将实际可用的内存空间缩小为了原来的一半
1.3 标记清除
老年代一般是由标记清除或是标记清除与标记整理的混合实现。
原理:算法分为 标记 和 清除 两个阶段。首先标记出所有需要回收的对象(标记),在标记完成后统一回收所有被标记的对象(清除)。
优点:
- 所有的操作都是在一块内存空间上完成的,不需要额外的空间
缺点:
- 标记 和 清除 两个过程的效率都不高:标记需要扫描1次,清除也需要扫描1次,两次扫描,耗时严重
- 标记清除后,会产生大量不连续的内存碎片,空间碎片太多可能会导致以后程序在运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾回收。
1.4 标记整理
标记整理一般发生在老年代区域。
原理:和标记清除算法一样,不同的是,在标记完后,不是直接清理可回收对象,而是让所有存活的对象都向一端移动,然后清理掉端边界以外的内存。
优点:
- 清理时,不会产生大量连续的内存碎片
缺点:
- 需要移动对象的成本