垃圾收集算法和垃圾收集器
1 、垃圾收集算法
1.1 标记-清除算法
先标记要回收的对象,在标记完成后统一回收所有被标记的对象。
缺点:标记和清除两个过程的效率较低;标记清除后会产生大量不连续的内存碎片。
1.2 复制算法
将内存容量划分成大小相等的两块,每次只使用其中一块,当这一块内存用完了,就将还存在的对象复制到另外一块,再清理掉已使用过的内存空间。
HotSpot虚拟机就是使用复制算法来回收年轻代的内在的,HotSpot虚拟机把堆内存分成年轻代和年老代,年轻代又分成Eden区、From Survivor区、To Survivor区,Eden和Survivor的默认大小比例是8:1,由参数SurvivorRatio=8控制,Eden负责为对象分配内存,当Eden的内存不足为新对象分配时,就会触发minor GC,先对Eden中不使用的对象所占用的对象进行清理,再将存活的对象拷贝到From Survivor,并将存活对象标记加1,直到标记满15次,就把对象迁移到老年代;然后继续为对象分配内存,对象可以在Eden和From Survivor这两个区分配内存,当Eden中的内存不足为新对象分配内存时,就会触发Minor GC,清理掉Eden区和From Survivor区里面不使用的对象,并且把Eden区和From Survivor区里面的存活对象复制到To Survivor区,并将存活对象的标记次数加1,以后的为新对象分配内存就在Eden区和To Survivor区分配。
1.3 标记-整理算法
先标记出可以回收的对象,再清理这些对象,再将存活的对象移到一起,然后再清理掉边界。
1.4 分代收集
商用的JAVA虚拟机一般把JAVA堆分成年轻代和老年代,年轻代由于对象的存活率低,采用复制算法;老年代由于对象的存活率高,采用“标记-清理 ”或者“标记-整理”算法。
2 、垃圾收集器
2.1 Serial收集器
是一个单线程收集器,但它在执行垃圾收集的时候,其他线程得全部暂停工作。
2.2 ParNew收集器
ParNew收集器是Serial收集器的多线程版本,它是多个线程在执行回收工作,但在执行回收工作时,其他所有线程也是要全部暂停工作的。
2.3 Parallel Scanvenge收集器
Parallel Scanvenge是一个新生代收集器,它也是使用复制算法的收集器,又是并行的多线程收集器。这个垃圾收集器更关注吞吐量,吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间)。它是多个线程在执行回收工作,但在执行回收工作时,其他所有线程也是要全部暂停工作的。
2.4 CMS收集器
CMS(Concurrent Mark Sweep)并发标记清除收集器是一种以获取最短回收停顿时间为目标的收集器,在JDK1.5中发布。会产生内存碎片。
整个过程分四个步骤。
(1) 初始标记
(2) 并发标记
(3) 重新标记
(4) 并发清除
其中初始标记和重新标记都是要停止其他所有线程的工作执行的。并发标记和并发清除可以与其他工作线程一起执行。
2.5 G1收集器
G1(Garbage-First)收集器是整体上基于标记-整理,从局部看是基于复制算法实现。不会产生太多的内存碎片。利用多CPU、多核环境,通过并发的方式让JAVA程序在执行垃圾回收的时候也能继续执行。
G1收集器的过程如下。
(1) 初始标记
(2) 并发标记
(3) 最终标记
(4) 筛选回收
其中初始标记是要停止其他所有线程的工作执行的,并发标记、最终标记和筛选回收可以与其他工作线程一起执行。