jvm垃圾收集器工作原理和应用(JVM垃圾收集器ParNewCMS)
jvm垃圾收集器工作原理和应用(JVM垃圾收集器ParNewCMS)
引言JVM的垃圾回收机制已经在上篇文章(JVM内存分配以及回收机制 )中分析完成,不过垃圾回收的真正实现还是垃圾收集器。本篇文章主要是结合了《深入了解JAVA虚拟机》书上的内容,结合我个人的一些理解,分析一下当前市面上常用垃圾回收器的优缺点,并给出各垃圾收集器适配的业务场景,为后面GC调优跨出必不可缺的一步。
常用的垃圾收集器截至目前为止,并没有一种完美的垃圾回收器或者说没有万能的回收器。我们只能比较各个垃圾收集器的优势与不足,根据具体的业务场景选择和业务最为接近的垃圾收集器。常用的垃圾回收器如下:
- Serial收集器:开启参数为-XX: UseSerialGC -XX: UseSerailOldGC,Serial为串行的垃圾收集器,Serial进行垃圾收集时,只会开启一条垃圾收集进程,并暂停其他所有的进程 去进行垃圾清理工作。
- 优势:简单高效,没有线程之间的交互,单线程的收集效率非常高
- 使用:有点真正意义上的"Stop The World"的感觉,一般此收集器都是和其他收集器搭配使用 ,或者作为CMS收集器的备选方案
- 回收算法:新生代采用复制算法,老年代采用标记整理算法
- ParNew收集器:开启参数为 -XX:UseParNewGC ,parnew收集器简单上来说就是serial收集器的多线程版本,除了利用多线程进行垃圾回收外,其余的回收算法、收集算法等方面都是和serial一致
- 优势:在内存空间较大时(线程之间的切换开销远低于多线程垃圾回收节约的时间)比searial更高效地进行垃圾回收
- 使用:一般配合CMS收集器使用
- Parallel Scavenge收集器:开启参数为 -XX: UseParallelGC,parallel scavenge收集器垃圾收集方式和parnew差不多,不过parallel scavenge收集器在利用CPU的效率上比起parnew有一个非常大的提高,即吞吐量上有一个质的提升
- 吞吐量:CPU中运行用户代码所消耗的时间与CPU总消耗量时间的比值
- 优势:提供了非常多的参数帮助用户找到最大吞吐量,如果比较关注吞吐量,parallel scavenge是一个不错的选择
- 回收算法:新生代采用复制算法,老年代采用标记整理算法
Parallel Scavenge收集器工作示意图
- CMS收集器(重点):开启参数为 -XX: UseConcMarkSweepGC,此收集器的设计目的是为了缩短gc造成的停顿时间,从而提高用户的使用体验。cms收集器的独特之处在于可以让垃圾收集线程与业务线程同时工作,同时cms收集器提供了非常多的参数给开发者,让cms在不断的参数优化之后,逐步的提高用户体验
- 优势:对垃圾进行并发收集,用户线程停顿时间短
- cms收集器回收详细步骤:
- 初始标记:此阶段会暂停所有线程,将GC Root直接引用的对象进行标记(这就是cms的聪明之处,只标记GC Root直接引用的对象,而不是将和GC Root有关联的像全部收集,大大降低了对象标记时间)
- 并发标记:此时会同时开启业务线程以及GC线程,GC线程会将和初始标记对象有关联的对象全部进行标记,而业务线程可以保证业务正常流转。当然因为此时业务线程正常运转,所以并发标记时无法标记出此期间产生的垃圾对象以及及时的对对象进行可达性分析,不过并发标记算法会纪律发生引用更新的地方
- 重新标记:此阶段会暂停所有线程,为了修正并发标记阶段因为业务线程运行而导致的对象引用更新,不过此阶段暂停线程的时间相比于并发标记阶段的时常来说,非常的短
- 并发清理:开启业务线程,并同步开启GC线程进行垃圾回收
- cms的缺点:cms的回收步骤不难看出,cms的缺点也比较明显
- 会和业务线程抢占资源,对CPU资源要求较高
- 并发清理时造成时出现的垃圾无法清理,必须等待下次gc时才能清理
- 回收算法为“标记-清除”,此算法会导致大量的内存空间碎片,如果需要避免此种情况,可以开启 -XX: UseCMSCompactAtFullCollection 参数 让JVM清除之后对存活的对象进行整理,不过此参数开启后会略微影响垃圾回收的效率
- 执行过程的不确定性,在并发清理的过程中,因为业务线程持续运行,此过程中可能出现再次占满老年代空间的情况,如果此情况一旦发生,cms马上会对jvm进行stop the world,改为serial收集器进行垃圾回收,为了预防此情况的发生,需要在系统运行过程中不断对CMS参数进行调优,最大可能减低此情况发生。
CMS垃圾收集器运行机制
- CMS收集器参数:
- -XX: UseConcMarkSweepGC:是否开启cms
- -XX:ConcGCThreads:cms并发GC线程数,此参数不是越大越好,需要根据机器的配置以及具体的业务进行设置
- -XX: UseCMSCompactAtFullCollection:full gc后进行内存碎片整理,达到减少内存碎片的效果
- -XX:CMSFullGCsBeforeCompaction:当开启了 UseCMSCompactAtFullCollection 参数后,通过此参数设置,设置多少次full gc后,进行内存整理工作,默认值为0,即每次full gc后都会进行碎片整理
- -XX:CMSInitiatingOccupancyFraction:使用cms收集器,设置触发full gc 的老年代内存占比阈值,默认为92,即老年代内存占用达到92%就会触发full gc
- -UseCMSInitiatingOccupancyOnly:此参数在开启CMSInitiatingOccupancyFraction参数后生效,因为jvm在每次gc后,会自动调整老年代内存阈值,如果此参数开启,则会一直使用CMSInitiatingOccupancyFraction参数配置的阈值,不会自动调整
- -XX: CMSScavengeBeforeRemark:在full gc前开启一次minor gc