GC基础知识

1、什么是垃圾

没有任何引用指向的一个对象或者多个对象(循环引用)

2、如何定位垃圾

  • 引用计数
  • 根可达算法

    3、常见的垃圾回收算法

  • 标记清除(mark sweep) - 位置不连续 产生碎片 效率偏低(两遍扫描)
  • 拷贝算法 (copying) - 没有碎片,浪费空间
  • 标记压缩(mark compact) - 没有碎片,效率偏低(两遍扫描,指针需要调整)

4、JVM 内存分配模型

  • 部分垃圾回收器使用的模型

    • 除Epsilon ZGC Shenandoah之外的GC都是使用逻辑分代模型
    • G1是逻辑分代,物理不分代
    • 除此之外不仅逻辑分代,而且物理分代
  • 新生代 + 老年代 + 永久代(1.7)Perm Generation/ 元数据区(1.8) Metaspace
    • 永久代 元数据 - Class
    • 久代必须指定大小限制 ,元数据可以设置,也可以不设置,无上限(受限于物理内存)
    • 字符串常量 1.7 - 永久代,1.8 - 堆
    • MethodArea逻辑概念 - 永久代、元数据
  • 新生代 = Eden + 2个suvivor区

    • YGC回收之后,大多数的对象会被回收,活着的进入s0
    • 再次YGC,活着的对象eden + s0 -> s1
    • 再次YGC,eden + s1 -> s0
    • 年龄足够 -> 老年代 (15 CMS 6)
    • s区装不下 -> 老年代
  • 老年代
    • 顽固分子
    • 老年代满了FGC Full GC
  • GC Tuning (Generation)
    • 尽量减少FGC
    • MinorGC = YGC
    • MajorGC = FGC

常见的垃圾回收器

  • Serial 年轻代 串行回收
    单CPU效率最高,虚拟机是Client模式的默认垃圾回收器。Serial回收器使用单线程进行垃圾回收,使用复制算法。在 HotSpot 虚拟机中,使用-XX:+UseSerialGC 参数可以指定使用Serial(新生代串行收集器)+ Serial Old(老年代串行收集器)。
  • PS 年轻代 并行回收
    新生代并行回收收集器也是使用复制算法的收集器。从表面上看,它和并行收集器一样都是多线程、独占式的收集器。但是,并行回收收集器有一个重要的特点:它非常关注系统的吞吐量。
    在启动参数中指定-XX:+UseParallelGC,会使用Parallel Scavenge(新生代并行回收收集器) + SerialOld的回收器组合
    如果使用-XX:+UseParallelOldGC,表示Parallel Scavenge(新生代并行回收收集器)+ Parallel Old(并行回收收集器)

  • ParNew 年轻代 配合CMS的并行回收

Serial回收器的多线程版本,只能用于新生代。使用复制算法,多线程并行工作。在多CPU主机上的性能高于Serial,单CPU主机上的性能低于Serial。
如果使用-XX:+UseParNewGC,表示ParNew(并行收集器)+ Serial Old(串行收集器)

  • SerialOld老年代 串行回收

Serial收集器的老年版本,独占式,单线程,使用的是标记--整理算法,这个收集器的目的也是用于Client模式下的虚拟机使用。

  • ParallelOld老年代 并行回收

是Parallel Scavenge收集器的老年版本,使用多线程和标记整理算法,注重吞吐量优先,在注重吞吐量和CPU资源铭感的场合,都可以考虑Parallel Scavenge加Parallel Old收集器。

  • ConcurrentMarkSweep 老年代 并发的, 垃圾回收和应用程序同时运行,降低STW的时间(200ms)

算法:三色标记 + Incremental Update
1.初始标记:Stop the world,只标记GC Roots能直接关联到的对象。
2.并发标记:GC Roots Tracing
3.重新标记:Stop the world,修正并发标记期间,因用户程序继续运行导致标记产生变动的那一部分对象的标记记录。
4.并发清除:并发清除可以和用户线程一起运行,所以总体上停顿的时间非常短。
但是CMS收集器有三个显著缺点:
1.对CPU资源敏感。
2.无法处理浮动垃圾。
3.收集结束后会产生大量碎片。

  • G1 (10ms) 算法:三色标记 + SATB

1.G1的设计原则是"首先收集尽可能多的垃圾(Garbage First)"。因此,G1并不会等内存耗尽(串行、并行)或者快耗尽(CMS)的时候开始垃圾收集,而是在内部采用了启发式算法,在老年代找出具有高收集收益的分区进行收集。同时G1可以根据用户设置的暂停时间目标  自动调整年轻代和总堆大小,暂停目标越短年轻代空间越小、总空间就越大;
  2.G1采用内存分区(Region)的思路,将内存划分为一个个相等大小的内存分区,回收时则以分区为单位进行回收,存活的对象复制到另一个空闲分区中。由于都是以相等大小的分区为单位进行操作,因此G1天然就是一种压缩方案(局部压缩);
  3.G1虽然也是分代收集器,但整个内存分区不存在物理上的年轻代与老年代的区别,也不需要完全独立的survivor(to space)堆做复制准备。G1只有逻辑上的分代概念,或者说每个分区都可能随G1的运行在不同代之间前后切换;
  4.G1的收集都是STW的,但年轻代和老年代的收集界限比较模糊,采用了混合(mixed)收集的方式。即每次收集既可能只收集年轻代分区(年轻代收集),也可能在收集年轻代的同时,包含部分老年代分区(混合收集),这样即使堆内存很大时,也可以限制收集范围,从而 降低停顿。

  • ZGC (1ms) PK C++ 算法:ColoredPointers + LoadBarrier