7款经典垃圾回收器

7款经典垃圾回收器

如果你想要最小化地使用内存和并行开销,请选serial GC+Serial Old;
如果你想要最大化应用程序的吞吐量,请选Parallel GC+Parallel old;
如果你想要最小化GC的中断或停顿时间,请选CMS GC+ParNew;

 

串行
对于交互较强的应用而言,这种垃圾收集器是不能接受的。一般在Javaweb应用程序中是不会采用串行垃圾收集器的。

Serial

优势:简单而高效(与其他收集器的单线程比),对于限定单个CPU的环境来说,Serial收集器由于没有线程交互的开销,专心做垃圾收集自然可以获得最高的单线程收集效率。
在HotSpot虚拟机中,使用-XX:+UseserialGc参数可以指定年轻代和老年代都使用串行收集器。
等价于新生代用serial Gc,且老年代用serial old Gc

Serial Old

内存回收算法使用的是标记-压缩算法。
Serial Old是运行在client模式下默认的老年代的垃圾回收器
Serial old在server模式下主要有两个用途:
①与新生代的ParallelScavenge配合使用
②作为老年代CMS收集器的后备垃圾收集方案

并行

ParNew

ParNew是Serial收集器的多线程版本。
Par是Parallel的缩写,New:只能处理的是新生代。
ParNew收集器除了采用并行回收的方式执行内存回收外,两款垃圾收集器之间几乎没有任何区别。ParNew收集器在年轻代中同样也是采用复制算法、"stop-the-world"机制。
ParNew是很多JVM运行在server模式下新生代的默认垃圾收集器。

Parallel scavenge

那么Parallel收集器的出现是否多此一举?
和ParNew收集器不同,Parallel scavenge收集器的目标则是达到一个可控制的吞吐量,它也被称为吞吐量优先的垃圾收集器。
自适应调节策略也是Parallel scavenge与ParNew一个重要区别。
高吞吐量则可以高效率地利用CPU时间,尽快完成程序的运算任务,主要适合在后台运算而不需要太多交互的任务。因此,常见在服务器环境中使用。例如,那些执行批量处理、订单处理、工资支付、科学计算的应用程序。

 

Parallel old

Parallel old收集器采用了标记-压缩算法,但同样也是基于并行回收和"stop-the-world"机制。

CMS

初始标记
在这个阶段中,程序中所有的工作线程都将会因为“Stop-the-world”机制而出现短暂的暂停,这个阶段的主要任务仅仅只是标记出GC Roots能直接关联到的对象。一旦标记完成之后就会恢复之前被暂停的所有应用线程。由于直接关联对象比较小,所以这里的速度非常快。

 

并发标记
从GC Roots的直接关联对象开始遍历整个对象图的过程,这个过程耗时较长但是不需要停顿用户线程,可以与垃圾收集线程一起并发运行。

 

重新标记
由于在并发标记阶段中,程序的工作线程会和垃圾收集线程同时运行或者交叉运行,因此为了修正并发标记期间,因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间通常会比初始标记阶段稍长一些,但也远比并发标记阶段的时间短。

 

并发清除
此阶段清理删除掉标记阶段判断的已经死亡的对象,释放内存空间。由于不需要移动存活对象,所以这个阶段也是可以与用户线程同时并发的

 

优点
并发收集、低延迟

 

缺点
①会产生内存碎片,导致并发清除后,用户线程可用的空间不足。在无法分配大对象的情况下,不得不提前触发Full GC。
②CMS收集器对CPU资源非常敏感。在并发阶段,它虽然不会导致用户停顿,但是会因为占用了一部分线程而导致应用程序变慢,总吞吐量会降低。
③CMS收集器无法处理浮动垃圾。可能出现“concurrent Mode Failure"失败而导致另一次 Full GC的产生。在并发标记阶段由于程序的工作线程和垃圾收集线程是同时运行或者交叉运行的,那么在并发标记阶段如果产生新的垃圾对象,CMS将无法对这些垃圾对象进行标记,最终会导致这些新产生的垃圾对象没有被及时回收,从而只能在下一次执行GC时释放这些之前未被回收的内存空间。

 

参数
-XX:+UseConcMarkSweepGC手动指定使用CMS 收集器执行内存回收任务。
开启该参数后会自动将-XX:+UseParNewGc打开。即: ParNew (Young区用)+CMs(Old区用)+Serial old的组合。
-XX:CMSInitiatingoccupanyFraction设置堆内存使用率的阈值,一旦达到该阈值,便开始进行回收。JDK5及以前版本的默认值为68,即当老年代的空间使用率达到68%,会执行一次CMS 回收。JDK6及以上版本默认值为92%如果内存增长缓慢,则可以设置一个稍大的值,大的阈值可以有效降低CMS的触发频率,减少老年代回收的次数可以较为明显地改善应用程序性能。反之,如果应用程序内存使用率增长很快,则应该降低这个阈值,以避免频繁触发老年代串行收集器。因此通过该选项便可以有效降低Full GC的执行次数。
-XX:+UseCMSCompactFullCollection用于指定在执行完Full GC后对内存空间进行压缩整理,以此避免内存碎片的产生。不过由于内存压缩整理过程无法并发执行,所带来的问题就是停顿时间变得更长了。
-XX:CMSFullGCsBeforeCompaction设置在执行多少次Full Gc后对内存空间进行压缩整理。
-Xx : ParallelCMSThreads设置CMS的线程数量。
CMS 默认启动的线程数是(ParallelGcThreads+3) / 4,
ParallelGcThreads 是年轻代并行收集器的线程数。当CPU资源比较紧张时,受到CMS收集器线程的影响,应用程序的性能在垃圾回收阶段可能会非常糟糕。

posted @ 2023-02-09 17:34  sugarstar  阅读(147)  评论(0)    收藏  举报