Java垃圾回收算法
JVN在进行垃圾回收时常常使用以下几种垃圾回收算法:
1. 复制算法(应用在新生代)
步骤
- Eden/FromSurvivor复制到ToSurvivor,年龄+1
当Eden区域空间占满时会触发第一次MinorGC将存活的对象拷贝到FromSurvivor区域,当Eden区域再次触发MinorGC时会扫描Eden和From两个区域进行垃圾回收,经过这次垃圾回收后还存活的对象会被复制到To区域(如果对象的年龄已经到了老年代的标准,则直接进入到老年区),同时把这些对象的年龄+1。
- 清空Eden/FromSurvivor区域
清空Eden和From区域,这时就是两个Survivor区域的交换,此时谁空谁就是To区域。
- ToSurvivor和FromSurvivor区域互换
互换Survivor区域,原来的ToSurvivor成为下次GC时的From区域。部分对象会在From区域和To区域来回复制,直到复制到15此(有JVM的-XX:MaxTenuringThreshold=n的n决定,默认是15次),最终如果对象年龄大于15次,将被划分到老年代区域。
优势
实现简单
劣势
需要将空间等分成两份,每次使用其中的一份,用完后将存活对象复制到另一个空间。造成空间浪费。
JVM在进行新生代垃圾回收时,认为新生代的对象都是朝生夕灭的,所以将两个空间的大小划分为8:2(1From+1To),使用复制算法进行新生代的垃圾回收算法支持。
2.标记清除算法(老年代)
步骤
- 标记出垃圾对象
- 统一清除待回收的垃圾对象
优势
整个堆都可以进行对象的内存分配,不会造成空间的浪费。
劣势
- 效率低:标记和清除两个阶段都需要把全部对象扫描一遍,这个过程是很耗时间的。
- 内存碎片:经历标记清除后堆内会有很多的内存碎片产生,会导致大对象在进行内存分配时无法找打连续可用的空间。
3.标记整理算法(老年代)
步骤
- 标记出垃圾对象
- 将存活对象往一端移动,直接清理末端垃圾数据即可
优势
- 空间不浪费:整个堆都可以进行对象的内存分配,不会造成空间的浪。
- 空间统一整理,不会产生内存碎片。
- 相对标记清除耗时短,只需要在标记阶段进行全堆扫描。
劣势
会进行对象移动,实现相对复杂
对象移动会增加回收成本,增加耗时和复杂度;不移动对象会增加内存的分配成本
4.分代回收算法(理论)
分代回收的理论
- 绝大部分对象都是朝生夕灭的
- 熬过回收次数越多的对象越难收集
按照对象年龄的不同将堆区域划分为新生代和老年代,根据各区域对象特征不同采用不同的垃圾回收算法,这就是分代回收算法。