介绍
JVM堆内存主要分为新生代和老年代,其中新生代占用1/3堆空间,老年代占用2/3堆空间,其中新生代又细分为Eden区、Survivor区、SurvivorFrom区,分别是8:1:1。JVM针对新生代和老年代分别提供了不同的垃圾收集器。针对新生代的垃圾收集器有:Serial、ParNew、Parallel Scavenge;针对老年代的垃圾收集器有:Serial Old、Parallel Old、CMS;还有不分新生代和老年代的垃圾收集器G1,G1垃圾收集器是针对不同区域的G1分区收集算法。
- 新生代:Serial(单线程复制算法)、ParNew(多线程复制算法)、Parallel Scavenge(多线程复制算法、提高吞吐量)
- 老年代:Serial Old(单线程标记整理法)、Parallel Old(多线程标记整理法)、CMS(多线程标记清除法)
- 不分新生代还是老年代:G1(分区收集算法、多线程标记整理法)
新生代:Serial、ParNew、Parallel Scavenge
- Serial:基于复制算法,单线程,用户线程停止
- ParNew:基于复制算法,多线程,用户线程停止
- Parallel Scavenge:基于复制算法,多线程,用户线程停止,可以调节垃圾回收的时间及吞吐量
老年代:Serial Old、Parallel Old、CMS
- Serial Old:基于标记整理法,单线程,用户线程停止
- Parallel Old:基于标记整理法,多线程,用户线程停止,可以调节垃圾回收时间和吞吐量
- CMS:基于标记清除法,多线程
CMS是为老年代设计的垃圾收集器,目的:达到最短的垃圾收集停顿时间,以达到系统的稳定性。基于标记清除法,垃圾回收过程如下:
- 初始标记:只标记和GC Roots直接关联的对象,停止用户线程
- 并发标记:标记其他需要垃圾回收的对象,不停止用户线程
- 重新标记:在并发标记过程中用户线程继续运行,导致垃圾回收的部分对象状态发生变化,所以对这部分对象重新标记,停止用户线程
- 并发清除:不停止用户线程,清除和GC Roots不关联的对象
分区收集算法:G1
G1垃圾收集器为了避免全区域垃圾收集引起的系统停顿,将堆内存划分为大小固定的几个独立区域,独立使用这些区域的内存资源。在后台维护一个优先级列表,根据允许的最长垃圾收集时间,优先回收垃圾最多的区域,确保G1垃圾收集器具备最高的垃圾收集效率。垃圾回收过程如下:
- 初始标记:只标记和GC Roots直接关联的对象,停止用户线程
- 并发标记:标记其余需要回收的对象,不停止用户线程
- 最终标记:由于并发标记过程中,用户线程没停止,导致一些对象状态发生变化,需要重新标记,此时停止用户线程
- 筛选回收:根据用户设置的期望的GC停顿时间回收(CMS在这一步不需要停顿),把每个区域中存活的对象复制到其他空的区域,并释放原来区域的内存,需要停止用户线程
G1和CMS的区别
- 过程不同:G1和CMS相比有一个最重要的区别就是并发清除的时候,CMS和用户线程一起工作,G1需要停止用户线程
- 垃圾回收方法不同:CMS采用了标记清除法,会产生内存碎片,而G1垃圾收集器采用了标记整理法,不会产生内存碎片
- 粒度不同:CMS垃圾收集器的目标是减少系统回收垃圾的停顿时间,G1可以精确的控制垃圾收集停顿时间,指定停顿时间,而CMS没法指定
- 使用方式不同:G1是不分新生代和老年代的,所以不需要和其他收集器配合使用;而CMS适用于老年代,需要配合Parallel Scavenge一起使用
- CMS的优点:并发收集,低停顿,因为并发标记和并发清除,不STW
- CMS的缺点:占用CPU资源,内存碎片,因为不STW,所以会产生新的垃圾对象(浮动垃圾)
- G1的优点:没有内存碎片,可设置期望的停顿时间