jvm 垃圾收集器基础

发布时间 2023-04-14 16:24:14作者: HANGYCHN

Serial 收集器

  • 它是单线程的收集器,只会使用一个线程进行垃圾收集工作
  • 它的优点是简单高效,对于单个 CPU 环境来说,由于没有线程交互的开销,因此拥有最高的单线程收集效率

ParNew 收集器

  • Serial 收集器的多线程版本
  • 除了 Serial 收集器,只有它能与 CMS 收集器配合工作
  • 默认开启的线程数量与 CPU 数量相同,可以使用 -XX:ParallelGCThreads 参数来设置线程数

Parallel Scavenge 收集器

  • 与 ParNew 一样是多线程收集器,跟 ParNew 最大的区别是能 GC 自适应调节策略
  • 其它收集器关注点是尽可能缩短垃圾收集时用户线程的停顿时间
  • 可以通过一个开关参数打开 GC 自适应的调节策略(GC Ergonomics),就不需要手动指定新生代的大小(-Xmn)、Eden 和 Survivor 区的比例、晋升老年代对象年龄等细节参数了。虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或者最大的吞吐量 和 最少的 STW问题

Serial Old 收集器

  • 是 Serial 收集器的老年代版本

Parallel Old 收集器

  • Parallel Scavenge 收集器的老年代版本
  • 在注重吞吐量以及 CPU 资源敏感的场合,都可以优先考虑 Parallel Scavenge 加 Parallel Old 收集器

CMS 收集器

老年代使用标记清除算法,寻找垃圾对象和回收流程分为以下4个阶段

  • 初始标记: 仅仅只是标记一下 GC Roots 能直接关联到的对象,速度很快,需要停顿
  • 并发标记: 进行 GC Roots Tracing 的过程(对所有的对象进行追踪),它在整个回收过程中耗时最长,不需要停顿
  • 重新标记: 为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,需要停顿
  • 并发清除: 不需要停顿

具有以下缺点:

  • 吞吐量低: 低停顿时间是以牺牲吞吐量为代价的,导致 CPU 利用率不够高
  • 标记-清除算法导致的空间碎片,往往出现老年代空间剩余,但无法找到足够大连续空间来分配当前对象,不得不提前触发一次 Full GC

G1 收集器

  • G1(Garbage-First),它是一款面向服务端应用的垃圾收集器,在多 CPU 和大内存的场景下有很好的性能
  • 堆被分为新生代和老年代,其它收集器进行收集的范围都是整个新生代或者老年代,而 G1 可以直接对新生代和老年代一起回收
  • G1 把堆划分成多个大小相等的独立区域(Region),新生代和老年代不再物理隔离(只是物理不隔离,还是存在新生代老年代等逻辑分区存在)
  • 整体来看是基于“标记 - 整理”算法实现的收集器,从局部(两个 Region 之间)上来看是基于“标记-复制”算法实现的
  • 可通过配置-XX:MaxGCPauseMills=n最大停顿时间

G1 和 CMS 区别

  • 使用范围不同
    • CMS 只能收集老年代,必须配合新生代的Serial和ParNew收集器一起使用才能完成整个 JVM 的垃圾回收
    • G1 自己就能整个 JVM 的垃圾回收工作
  • STW的时间
    • CMS收集器以最小的停顿时间为目标的收集器
    • G1收集器可预测垃圾回收的停顿时间(通过配置-XX:MaxGCPauseMills=n最大停顿时间)
  • 内存碎片
    • CMS收集器是使用“标记-清除”算法进行的垃圾回收,容易产生内存碎片
    • G1收集器使用的是“标记-整理”和“标记-复制”算法,进行了空间整合,没有内存空间碎片