常见的垃圾回收器:
-
- Serial
- Serial Old
- Parallel Scavenge
- Parallel Old
- ParNew
- CMS
- G1
- ZGC
- Shenandoah
- Epsilon
下图已经列出来了这,其中Epsilon是debug使用的,不用过分关注;最常见的组合有:Serial +Serial Old 、Parallel Scavenge + Parallel Old 、ParNew + CMS。G1之前都是不仅在逻辑上是分代的而且在物理层面上也是分代的;G1只是在逻辑上分代;G1之后完全不分代,但是在生产环境使用的很少;
1、Serial
当垃圾收集器工作时所有工作线程全部停止,这里线程停下来一定会停在一个安全点上;
safe-point :线程停止(需要找到一个安全点上线程停止),因为停顿的时间长,现在很少用;
2、Serial Old
这个垃圾收集器用在老年代,它用的是mark-sweep的算法,他用的是单线程;
a stop-the-world
mark-sweep-compact collector that uses a single GC thread(使用单个GC线程的标记-清理-收集器).
3、Parallel Scavenge
a stop-the-world
Copying collector which uses multiple GC threads(使用多个GC线程的复制收集器).
如果你在JVM没有做任何的调优的话,默认使用的是:parallel scavenge +parallel old 简称(ps + po)
Parallel Scavenge 与Serial的区别:Parallel Scavenge 是多线程清理垃圾,后者为单线程清理垃圾。
4、Parallel Old
a compacting collector that uses multiple GC threads(使用多个GC线程的压缩收集器).
整理算法
5、ParNew
其实就是parallel new 的意思,和Parallel Scavenge没有很大的区别,就是它的新版本,做了一些的增强以便能够让它和CMS有更好的配合使用,CMS在某个特定的阶段会和Parallel New 同时运行。在工作的时候其余的线程不能够工作,必须等GC回收器结束后才可以。
Parallel New 和 Parallel Scavenge 区别:
-
- parallel new 的响应时间优先
- 能够配合CMS
- parallel scavenge 的吞吐量优先
6、CMS
CMS非常重要,它诞生了一个里程碑,以前的垃圾回收器在工作的时候其他的线程都要停下来,等我工作完,才能工作,CMS的出现消除了这个问题,与此同时CMS也带来了很多问题,以至于目前的所有的JDK版本默认都不是使用它。
-
- CMS的全拼:concurrent mark sweep
- A mostly concurrent , low-pause collector
- Four phases:
-
- initial mark (初始标记 STW开始标记)
- concurrent mark (并发标记和应用程序同时进行)
- remark (重新标记又是一个STW 在并发标记中产生的新垃圾 在这里进行重新标记 这里是使用多线程)
- concurrent sweep(并发清理的过程中也会产生新的垃圾 这个垃圾叫做浮动垃圾)
6.1、从线程角度理解:
垃圾回收器在工作的时候,垃圾回收的线程和工作线程同时进行,叫做:concurrent mark sweep;当内存比较小的情况下,清理垃圾的速度比较快没有问题,当内存越来越大较的时候,大到什么程度呢?大到你用多少线程进行清理的都需要很长一段时间,以前10G的内存的时候使用默认的ps+po大概需要的时间为11s。
为什么会出现并发垃圾回收器? 并发垃圾回收器出现的原因是因为忍受不了STW.
6.2、下面来解释一下CMS常见的几个阶段:
第一个阶段叫做CMS initial mark(初始标记阶段)这个阶段很简单,就是直接找到最根上的对象,然后进行标记,其他的对象不标记。
第二个阶段是CMS concurrent mark(并发标记)据统计百分之八十的时间都浪费在这里,因此它把这块耗时最长的阶段和我们的应用程序同时进行,对于客户来说感觉上可能慢了点,但是至少还有反应,这里的并发标记是一边产生垃圾一边进行跟着标记,这个过程很难完成;
第三阶段是CMS remark (重新标记)这里又是一个STW,在上一个并发标记的过程中产生的新垃圾在这个阶段进行标记,这个时候需要停顿,但是时间不会很长,毕竟只是上一步很短时间内产生的新垃圾;
第四阶段是concurrent sweep(并发清理)并发清理也有他的问题,在并发清理的过程中也会产生新的垃圾,这个垃圾叫做浮动垃圾,这个浮动垃圾就要等下一次CMS来清理了;
什么条件下会触发CMS呢?老年代分配不下了,这时会触发CMS,这里的初始标记是单线程,重新标记是多线程。
6.3、CMS的缺点:CMS出现问题后会调用Serial Old使用单线程进行标记压缩;
CMS的两大问题:
memory fragmentation 内存的碎片:这个是比比较严重的一个问题,如果内存超级大,产生了很多的碎片,这就会浪费很多的空间,其实CMS设计出来就是应付几百兆的内存至上G的内存,有的人拿它来应付很大内存就会出现问题,因为一旦老年代产生很多碎片,从新生代过来的对象就会出现找不到空间的情况,这叫做:PromotionFailed找不到空间。这时候它干了一件事情,把Serial Old 请出来,让它用一个线程在这里进行标记压缩。
floating garbage浮动垃圾:当出现Concurrent Mode Failure 和 PromotionFailed时,说明碎片较多,Old区内存分配不下,会调用Serial Old。并不是说使用了CMS之后这个问题没办法避免,可以降低触发CMS的阈值。
解决方法降低CMS的阈值: -XX:CMSInitiatingOccupancyFraction 92% 可以降低这个值,让CMS保持老年代有足够的空间。
Remark阶段的算法:
怎么才能进行并发标记呢 非常的复杂,CMS采用的是三色标记+Incremental Update 算法。
-
-
- 三色扫描算法:白灰黑
- 在并发标记时,引用可能发生变化,白色对象有可能会被错误回收
- 解决方法:SATB (snapshot at the beginning) 在起始的时候做一个快照
- Incremental Update : 当一个白色对象被一个黑色对象引用时,将黑色对象重新标记为灰色,让垃圾回收器重新扫描;
-
常见的垃圾回收器就介绍这么多,下一篇会给大家介绍一下 PS+PO;如果写的有误的地方还请大佬指出