性能优化-各种GC用法和关系

原创
2022/05/12 17:05
阅读数 522

常见的垃圾收集器有Serial GC、ParNew GC、CMS GC、Parallel GC、G1 GC

Serial GC:

  • 优点:单线程精简的GC实现,无需维护复杂的数据结构,初始化简单,是client模式下JVM默认选项。最古老的GC。老年代使用Serial Old GC
  • 缺点:会进入"Stop-The World"状态。
  • 命令:-XX:+UseSerialGC
  • 日志:DefNew是新生代,Tenured是老年代

ParNew GC:

  • 新生代GC实现,是SerialGC的多线程版本,最常见的应用场景是配合老年代的CMS GC 工作。
  • 命令:-XX:+UseParNewGC
  • 日志:ParNew是新生代,Tenured是老年代

CMS(Concurrent Mark Sweep)GC:

  • 优点: 基于标记-清除(Mark-Sweep)算法,尽量减少停顿时间(停顿优先)。
  • 缺点: 存在碎片化问题,在长时间运行的情况下会发生full GC,导致恶劣停顿。会占用更多的CPU资源,和用户争抢线程。在JDK 9中被标记为废弃。
  • 命令: 老年代使用CMS GC。同时年轻代 触发多线程ParNew GC
  • 日志: ParNew是新生代,CMS是老年代

Parrallel GC:

  • 在JDK8等版本中,是server模式JVM的默认GC选择,也被称为吞吐量优先的GC,算法和Serial GC相似。(吞吐量优先的 GC
  • 特点是老生代和新生代GC并行进行,更加高效。
  • 命令:-XX:+UseParallelGC (表明新生代用Parrallel GC) -XX:+UseParallelOldGC (表明老年代使用Parrallel Old GC)  二者可以相互激活。
  • 日志:PSYoungGen是新生代,ParOldGen是老年代

G1 GC:

  • 兼顾了吞吐量和停顿时间的GC实现,是Oracle JDK 9后默认的GC
  •  可以直观的设值停顿时间,相对于CMS GC ,G1未必能做到CMS最好情况下的延时停顿,但比最差情况要好得多
  • G1 仍存在分代的概念,使用了Region棋盘算法,实际上是标记-整理(Mark-Compact)算法,可以避免内存碎片,尤其是堆非常大的时候,G1优势更明显。
  • G1 吞吐量和停顿表现都非常不错。
  • 命令:-XX:+UseG1GC
  • 日志:garbage-first heap

ZGC:

  • 持TB级别:根据官方文档来看,在Jdk11时ZGC可支持的最大内存为4TB,在jdk⒀可以支持16TB。持TB级别:根据官方文档来看,在Jdk11时ZGC可支持的最大内存为4TB,在jdk⒀可以支持16TB。
  • 最大停顿时间不超过10ms:之所以能控制在10ms以下,是因为它的停顿时间主要跟Root扫描有关,而跟root数量和堆的大小没有关系。
  • ZGC内部是以Region的方式进行内存布局的,暂时没有设置分代,使用读屏障、颜色指针等技术来实现可并发的标记–整理算法的,且低延迟,Region分为大中小三种类型:
    1、小型Region(small Region):容量为2mb,用于放置小于256kb的对象。
    2、中型Region(medium Region):容量为4mb,用于放置容量大于等于256kb但小于4mb的对象。
    3、大型Region(large Region):容量不固定,大小可变,但必须是2的整数倍,且大小大于等于4mb的对象。
  • 命令:-XX:+UnlockExperimentalVMOptions -XX:+UseZGC

那么还有Young GC 、Old GC、Mixed GC、Full GC又是什么呢?

首先这些GC不是回收器,而是垃圾收集,其实正对对HotSpot VM的实现, 里面的GC按照回收区域又分两大类型:

  • 部分收集Partial GC
        1、新生代收集  Minor GC / Young GC:新生代(Eden\S0,S1)的垃圾收集,在年轻代中的Eden内存区域被占满之后,实际上就需要触发年轻代的gc
        2、老年代收集  Major GC / Old GC:老年代GC(目前只有CMS GC 有单独的老年代收集的行为)经常说Full GC 就是老年代收集
        3、混  合 收 集  Mixed GC:收集整个新生代和部分老年代的 垃圾收集(目前只有G1 GC 有这种收集的行为

  • 整堆收集Full GC:收集整个JAVA堆和方法区的垃圾收集

Young GC 、Old GC、Mixed GC、Full GC触发时间 

  • 新生代收集  Minor GC / Young GC:一般就是在新生代的Eden区域满了之后就会触发,采用复制算法来回收新生代的垃圾。
  • 老年代收集  Major GC / Old GC
    1. 老年代可用的连续内存空间 Young GC后升入老年代平均值,说明本次Young GC后可能升入老年代的对象大小,可能超过了老年代当前可用内存空间。此时必须先触发一次Old GC给老年代腾出更多的空间,然后再执行Young GC。

    2. 执行Young GC之后有一批对象需要放入老年代,老年代就是没有足够的内存空间存放这些对象,此时必须立即触发一次Old GC。
    3. 老年代内存使用率超过了92%,也要直接触发Old GC,当然这个比例是可以通过参数调整
  • 整堆收集的Full GC:
    1. JVM的实现机制里,其实在Old GC几种条件达到的时候,他触发的实际上就是Full GC,这个Full GC会包含Young GC、Old GC和永久代的GC。
    2. 方法区不足就触发Full GC
    3. System.gc()
  • 混  合 收 集  Mixed GC:是只有G1垃圾收集器才会触发的, mixed gc是指新生代gc+部分老年代gc,注意是部分,不是对整个老年代进行gc。当老年代的内存使用率达到某个阈值就会触发混合GC

如何选择GC(JKD9之前的版本)

  • 如果你的程序追求低延迟,用户交互度较为频繁,那你可以采用ParNew + CMS组合(这也是淘宝早期的选择,但后面采用了自研JVM)。
  • 如若你的程序追求高吞吐,后台计算工作较多,那么Parallel Scavenge + Parallel Old这组PS+PO的收集器会更适合你。
  • 单核或双核的机器时,那么最经典的Serial + Serial Old组合绝对是你的最佳选择。

 

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
0 收藏
1
分享
返回顶部
顶部