垃圾收集器
垃圾收集器
在java虚拟机中,有7个垃圾收集器,3个作用于年轻代,3个作用于老年代,还有G1是可以既作用于年轻代,也可以作用于老年代。
图中连线的表示可以组合使用。
Serial
- 新生代收集器,可以和Serial Old,CMS组合使用;
- 单线程独占式回收,会产生Stop The World现象;
- 采用复制算法
- client模式年轻代默认算法
- GC日志关键字:DefNew(Default New Generation)
ParNew
- 新生代收集器,可以和Serial Old, CMS组合使用;
- 多线程独占式回收,会产生Stop The World现象;
- 采用复制算法
- server模式年轻代默认算法
- 使用-XX:ParallelGCthreads参数来限制垃圾回收的线程数
- GC日志关键字:ParNew(Parallel New Generation)
Paralle Scavenge
- 新生代收集器,可以和Serial Old、ParallelOld组合使用
- 多线程独占式回收,会产生Stop The World现象;
- 采用复制算法
- 该收集器非常注重系统的吞吐量,提供了以下参数来调节系统的吞吐量
- -XX:MaxGCPauseMillis:设置最大垃圾收集停顿时间,单位为毫秒。系统会根据最大垃圾收集停顿时间来调节虚拟机的java堆大小,一个小的堆回收时间更小,但回收次数会增加,导致系统的吞吐量减小。
- -XX:GCTimeRatio:设置吞吐量的大小(即垃圾回收时间占总时间的比率)设置越小,系统就会根据值设置一个更大的堆,减少垃圾回收的次数,增大吞吐量,但是单次垃圾回收时间会边长。
- -XX:UseAdaptiveSizePolicy:参数开关,启动后系统动态自适应调节各参数,如-Xmn、-XX:SurvivorRatio等参数,寻找到堆大小,吞吐量和停顿时间之间平衡点。
- GC日志关键字:PSYoungGen
Serial Old
- 老年代收集器,可以和所有的年轻代收集器组合使用
- 采用标记压缩算法
- 采用单线程独占式算法,会产生Stop The World现象;
- GC日志关键字:Tenured
Parallel Old
- 老年代收集器,只能和Parallel Scavenge组合使用
- 采用标记压缩算法
- 采用多线程独占式算法,会产生Stop The World现象;
- GC日志关键字:ParOldGen
CMS( Concurrent Mark Sweep )
- 老年代收集器, 可以和Serial、ParNew组合使用
- 采用标记清除算法
- UserCMSCompactAtFullCollection:默认开启,FullGC时进行内存碎片整理,整理时用户进程需停止,即发生Stop The World
- CMSFullGCsBeforeCompaction:设置执行多少次不压缩的Full GC后,执行一个带压缩的(默认为0,表示每次进入Full GC 时都会进行碎片整理
- CMS是并发收集的,就是垃圾回收和用户程序同时进行,但某些阶段还是独占式的,这些阶段还是会出现Stop The World现象
- 初始标记:独占式的,不能和用户程序同时进行,会Stop the world ,这只是标记根对象
- 并发标记: 进行GC Roots Tracing,时间长,和用户程序同时进行,不发生用户进程停顿
- 预清理:和用户程序并发执行,为正式清理做准备和检查,预清理还会尝试控制一次停顿的时间。
- 重新标记:独占式的,不能和用户程序同时进行,会Stop the world 。因为并发标记是和用户程序同时进行的,在标记的时候,还有垃圾对象不断产生,重新标记就是为了标记那部分对象的。
- 并发清除:清除垃圾对象,是可以和用户进行同时进行的。
- 并发重置:垃圾回收完成,重新初始化CMS数据结构和数据。
- -XX:CMSInitiatingOccupancyFraction 指定当内存使用率到达多少时,执行一次CMS回收,因为CMS回收的时候依然会产生垃圾对象,所以不能等内存满了才来回收。
G1回收器
G1回收器时JDK1.7正式使用的全新垃圾回收器,G1回收器使用分代和分区算法。分代算法就是依然区分年轻代和老年代,依然后eden区和survivor区。分区算法就是不要求整个eden区,年轻代或者老年代都连续。
G1的收集过程
- 新生代GC
- 并发标记周期
- 混合收集
- 如果需要,可能会进行Full GC
G1的新生代GC
一旦eden区被占满,G1的新生代GC就会发生。
上图中eden区被清空,survivor区保留一部分,old区增多。
G1垃圾收集过程:
1,初始标记:stop the world 标记GC Roots,修改TAMS指针的值(TAMS是用来标识在回收过程用户线程新分配的对象地址区间,这些对象不用参与本次GC,因此要调整TAMS指针,防止下一阶段GC会标记到这些对象)
2,并发标记:从GC Roots开始进行可达性分析,扫描整个堆所有垃圾对象,扫描完成还有重新处理SATB记录(SATB是在GC过程中用户线程删除了的对象引用,因此需要处理这些变动的对象引用)
3,最终标记:stop the world,因此并发标记多次是和用户线程一起执行的,因此在处理SATB的过程,用户线程还会删除对象引用,SATB仍然会增加,因此需要stop the world来处理剩下的少量SATB记录。
4,筛选回收:stop the world 对各个Region的回收价值和成本进行排序,根据用户期望的停顿时间来回收。因为用的是复制算法回收,因此需要移动存活对象,因此必须暂停用户线程。
G1的优点:1,使用Region划分内存空间,回收垃圾多的Region,控制回收停顿的时间。
G1的缺点:1,需要记录自己和各个Region之间的对象引用,需要耗费Java堆容量10%至20%的额外内存。