JVM各代的介绍,请参考上篇博客的介绍。
一、垃圾回收的一般步骤
1、首先,所有新生成的对象都是放在年轻代的Eden分区的,初始状态下两个Survivor分区都是空的。年轻代的目标
就是尽可能快速的收集掉那些生命周期短的对象。
2、当Eden区满的的时候,小垃圾收集就会被触发。
3、当Eden分区进行清理的时候,会把引用对象移动到第一个Survivor分区,无引用的对象删除。
4、在下一个小垃圾收集的时候,在Eden分区中会发生同样的事情:无引用的对象被删除,引用对象被移动到另外一个
Survivor分区(S1)。此外,从上次小垃圾收集过程中第一个Survivor分区(S0)移动过来的对象年龄增加,然后被移
动到S1。当所有的幸存对象移动到S1以后,S0和Eden区都会被清理。注意到,此时的Survivor分区存储有不同年龄的
对象。
5、在下一个小垃圾收集,同样的过程反复进行。然而,此时Survivor分区的角色发生了互换,引用对象被移动到S0,幸存
对象年龄增大。Eden和S1被清理。
6、这幅图展示了从年轻代到老年代的提升。当进行一个小垃圾收集之后,如果此时年老对象此时到达了某一个个年龄阈值
(例子中使用的是8),JVM会把他们从年轻代提升到老年代。
7、随着小垃圾收集的持续进行,对象将会被持续提升到老年代。
8、这样几乎涵盖了年轻一代的整个过程。最终,在老年代将会进行大垃圾收集,这种收集方式会清理-压缩老年代空间。
二、垃圾回收器的种类
1、串行收集器:
在Java SE 5和6中,串行收集器是客户端环境(client-style machines)机器的默认设置。在这种情况下,小垃圾收集和
大垃圾收集都是串行进行的(使用单个的虚拟CPU)。
使用的算法说明:
串行收集器在年轻代使用的是拷贝算法,这个算法比较简单,在这里不做详述。而年老代和持久代使用标记-清扫-压缩(
mark-sweep-compact)算法。标记阶段,收集器识别哪些对象仍然活着。清扫阶段“扫荡”整个代,识别垃圾。之后,收集
器执行平移压缩(sliding compaction),将存活的对象平移到代的前端(持久代类似),相应的在尾部留下一整块连续的
空闲空间。压缩后,以后的分配就可以在年老代和持久代使用空闲指针(bump-the-pointer)技术。这种压缩算法能够在堆
上迅速分配内存块。
2、并行收集器
并行垃圾收集器在年轻代使用多线程进行垃圾回收。默认情况下,在N个CPU的主机上,并行垃圾收集器使用N个垃圾收集器
线程进行垃圾回收。垃圾收集器线程的个数可以在命令行进行设置:-XX:ParallelGCThreads=<期望的数值>
在单核的CPU上,尽管我们请求设置的是并行垃圾收集器,但JVM还是使用默认的垃圾收集器。在两个CPU的主机上,并行
垃圾收集器与默认的串行垃圾收集器所表现出来的性能相当,年轻代的垃圾收集器暂停时间与两个以上CPU的主机相比也有
所减少。
使用的算法说明:
年轻代:与串行垃圾收集器年轻代相同的拷贝算法,只不过是该算法的并行版本,使用多个CPU并行的运行,减少了垃圾收
集的开销,因此增加了吞吐量。
年老代:与串行垃圾收集器老年代想听的标记-清扫-压缩(mark-sweepcompact)算法,只不过是该算法的并行版本。
3、并发标记清理收集器
并发标记清理收集器(CMS,又叫作并发低暂停收集器)在老年代进行收集。由于垃圾收集能使用应用线程的并发进行大多数
的垃圾收集工作,所以它降低了应用程序的暂停时间。
正常说来,并发低暂停的收集器对存活对象不进行复制和压缩的工作。这种情况下,垃圾收集器没有移动任何存活对象。如果
因此而带来了内存的碎片问题,那就为其分配一个更大的堆。
注意:CMS收集器在年轻代使用和并行收集器一样的算法。
4、G1 垃圾回收器
在Java 7中可以使用G1垃圾回收器,它设计的初衷是用于长期取代CMS收集器。G1垃圾收集器是一个并行、并发,同时也是基于
增量整理的低暂停垃圾收集器。与前面所描述的垃圾收集器相比,从布局方面与它们有很大的不同。
和CMS不同,G1会随时间推移对堆栈进行压缩,压缩消除了潜在的碎片问题,确保长时间运行的操作流畅和一致。
G1比CMS预测性更佳,这都是由于消除了碎片问题带来的好处,再也没有CMS中停止期间出现的负面影响,另外,G1有一个暂停
预测模型,允许它满足(或很少超过)暂停时间目标。