JVM垃圾收集器
先看两个图:
- Java垃圾收集器的类型:
- 垃圾收集器工作的区域:
常见垃圾回收器
不同的垃圾回收器,适用于不同的场景。常用的垃圾回收器:
- Serial:串行回收器是单线程的一个回收器,简单、易实现、效率高;在进行垃圾收集时候,必须暂停其他所有的工作线程直到它收集结束,新生代使用复制算法。
- ParNew:并行回收器是Serial的多线程版,可以充分的利用CPU资源,减少回收的时间;在垃圾收集时,会Stop-the-World暂停其他所有的工作线程直到它收集结束。
- Parallel Scavenge:吞吐量优先回收器,侧重于吞吐量的控制;新生代使用复制算法。
- CMS:Concurrent Mark Sweep,并发标记清除回收器是一种以获取最短回收停顿时间为目标的回收器,该回收器是基于“标记-清除”算法实现的。CMS采用标记清除算法,默认并不使用标记整理算法,可能会产生很多碎片;
- Serial old: 老年代的串行回收器,是单线程的一个回收器,采用标记-整理算法;
- Parallel old:老年代基于吞吐量的回收器;使用多线程的标记-整理算法;
- G1:既可以回收新生代也可以回收老年代,JDK1.9默认G1垃圾回收器。
JDK默认垃圾回收器:
- jdk7环境下,默认使用 Parallel Scavenge(新生代)+ Serial Old(老年代)
- jdk8环境下,默认使用 Parallel Scavenge(新生代)+ Serial Old(老年代)
- jdk9环境下,默认使用 G1(新生代+老年代)
CMS之promotion failed&concurrent mode failure
- promotion failed:一般是进行Minor GC的时候,发现Survivor空间不够,所以,需要移动一些新生代的对象到老年代,然而,有些时候尽管老年代有足够的空间,但是由于CMS采用标记清除算法,默认并不使用标记整理算法,可能会产生很多碎片,因此,这些碎片无法完成大对象向老年带转移,因此需要进行CMS在老年代的Full GC来合并碎片;但是Full GC导致的stop-the-wold是难以接受的。
解决方法:可以让CMS在进行一定次数的Full GC(标记清除)的时候进行一次标记整理算法,CMS提供了以下参数来控制:
-XX:UseCMSCompactAtFullCollection
-XX:CMSFullGCBeforeCompaction=5
也就是CMS在进行5次Full GC(标记清除)之后进行一次标记整理算法,从而可以控制老年代的碎片在一定的数量以内,甚至可以配置CMS在每次Full GC的时候都进行内存的整理。
- concurrent mode failure:CMS GC线程和业务线程并发运行时业务线程将大对象放入老年代,而此时老年代空间不足;或者在做Minor GC的时候,新生代Survivor空间放不下,需要放入老年代,而老年代也放不下而产生的。此时需要尽快回收老年代里面的不再被使用的对象,停止所有的线程,同时终止CMS GC,直接进行Serial Old GC。
解决方法:
调低触发CMS GC执行的阀值,CMS GC触发主要-XX:CMSInitiatingOccupancyFraction值决定,默认情况是当旧生代已用空间为68%时,即触发CMS GC,在出现concurrent mode failure的情况下,可考虑调小这个值,提前CMS GC的触发,以保证旧生代有足够的空间。
上面二者总结一句话就是:使用标记整理清除碎片和提早进行CMS GC操作。
GC之间如何选择垃圾收集器:
参考链接:CMS之promotion failed&concurrent mode failure,G1垃圾收集器,GC之7大垃圾收集器详解
还没有评论,来说两句吧...