垃圾收集器

时间:2022-12-31 08:55:25


1.术语
(1).吞吐量
CPU用于运行用户代码的时间与CPU总消耗的比值。

(2).全局停顿(Stop The World)
是在垃圾回收过程中,需要将JVM内存冻结的一种状态。在全局停顿状态下,除GC线程外,Java其它线程都是停止执行的,本地方法可以执行,但是无法与JVM交互。JVM调优就是尽量减少全局停顿时间,但是并不是越小越好,因为全局停顿时间的减少是以牺牲吞吐量和新生代空间为代价的。

(3).并行收集
指多个垃圾回收线程并行工作,但在回收过程中,用户线程处于等待状态。

(4).并发收集
用户线程和垃圾回收线程同时工作。

2.分类

七种垃圾回收器以及其作用的内存区域如下图所示,连线表示可以配合使用。

垃圾收集器

3.Serial收集器

(1).概念

Serial收集器是最基本、发展历史最久的收集器,采用复制算法的单线程的收集器。单线程一方面意味着它只会使用一个CPU或者一个线程去完成垃圾回收工作,另一方面也意味着它进行垃圾收集时必须暂停其他线程,直到它收集结束为止。

垃圾收集器

(2).特点

  • 使用复制回收算法
  • 单线程

(3).使用场景

  • 虚拟机运行在Client模式下
  • 单核服务器

4.ParNew收集器

(1).概念

Parnew收集器其实是Serial收集器的多线程版本,除了使用多线程进行垃圾收集外,其余行为和Serial收集器完全一样。

垃圾收集器

(2).特点

  • 使用复制回收算法
  • 多线程(可以使用-XX:ParallelGCThreads设置线程数,一般设置为CPU核数即可)

(3).使用场景

  • 虚拟机运行在Server模式下
  • 多核服务器

5.Parallel Scavenge收集器

(1).概念

Parnew收集器其实是Serial收集器的多线程版本,除了使用多线程进行垃圾收集外,其余行为和Serial收集器完全一样。

垃圾收集器

(2).特点

  • 使用复制回收算法
  • 多线程
  • 可以达到一个可控制的吞吐量

虚拟机提供了-XX:MaxGCPauseMills和-XX:GCTimeRatio两个参数来精确控制最大垃圾收集停顿时间和吞吐量大小。不过停顿时间并不是越小越好,GC停顿时间的缩短是以牺牲吞吐量和新生代空间换取的。
Parallel Scavenge收集器还有一个参数-XX:UseAdaptiveSizePolicy,这是一个开关参数,这个参数打开之后,就不需要手动指定新生代的Eden和Survivor区参数细节了,虚拟机会根据当前系统的运行情况动态调整这些参数以提供最合适的停顿时间或者最大的吞吐量。

(3).使用场景
注重吞吐量的场景

6.Serial Old收集器

(1).概念

Serial Old收集器是Serial收集器的老年代版本,采用标记整理算法的单线程的收集器。

垃圾收集器

(2).特点

  • 使用标记整理回收算法
  • 单线程

(3).使用场景

  • 可以和Serial、ParNew、Parallel Scavenge新生代收集器配合使用
  • 作为CMS收集器的备用

7.Parallel Old收集器

(1).概念

Parallel Old收集器是Parallel Scavenge收集器的老年代版本,采用标记整理算法的多线程的收集器。

垃圾收集器

(2).特点

  • 使用标记整理回收算法
  • 多线程
  • 可控制的吞吐量

(3).使用场景

  • 可以和Parallel Scavenge新生代收集器配合使用
  • 关注吞吐量的场景

8.CMS收集器

(1).概念

使用标记清除算法以获取最短全局停顿时间为目标的收集器。

垃圾收集器

(2).收集步骤

  • 初始标记:标记GCRoots对象能直接关联到的对象,存在全局停顿。
  • 并发标记:标记GCRoots对象能关联到的所有对象,因为并发执行,所以不存在全局停顿。
  • 重新标记:修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,存在全局停顿。
  • 并发清除:回收内存空间,因为也是并发执行,所以不存在全局停顿。

(3).优点

  • 全局停顿时间比较短
  • 大多数过程是并发执行

(4).缺点

  • 内存碎片,不能等到老年代几乎满了才开始收集(Serial Old作为后备)
  • 并发执行导致吞吐量降低
  • 无法处理浮动垃圾,不能一次收集完垃圾

(5).使用场景

  • 系统全局停顿时间短,响应速度快的场景

9.G1

(1).概念

使用G1回收器的Java堆内存布局与其他收集器有很大差别,它将整个Java堆划分为多个大小相等的独立区域Region,虽然还保留有新生代和老年代的概念,但新生代和老年代不再是物理隔离的了,它们都是一部分(可以不连续)Region的集合。

然后跟踪每个Region里面的垃圾大小,评估回收该区域的垃圾后获得的内存价值,最后构建一个优先列表,根据允许的收集时间,优先回收价值高的Region,以获得更高的垃圾回收效率。

垃圾收集器

(2).Young GC

  • 所有Eden Region都满的时候,就会触发Young GC
  • Eden Region里存活的对象会被转移到Survivor Region
  • 原先Survivor Region里的存活对象,会被转移到新的Survivor Region,或者晋升到Old Region
  • 空闲的Region会被放到空闲列表中,等待下次被使用

(3).Mixed GC
老年代大小占整个堆的百分比达到一定阈值就会触发Mixed GC,Mixed GC会回收所有的Young Region和部分Old Region。

  • 初始标记:标记GCRoots对象能直接关联到的对象,存在全局停顿。
  • 并发标记:标记GCRoots对象能关联到的所有对象,因为并发执行,所以不存在全局停顿。
  • 最终标记:修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,存在全局停顿。
  • 筛选回收:对各个Region的回收价值进行评估和排序,并选择一些价值高的Region进行回收,存在全局停顿。
  • 选择一些Region构成一个回收集
  • 把需要回收Region里的存活对象复制到空的Region中
  • 删除掉需要回收的Region

(4).Full GC
复制对象内存不够,或者无法分配足够内存时,会触发Full GC,Full GC模式下,使用Serial Old模式,G1优化原则是尽量减少Full GC。

  • 增加预留空间(增大-XX:G1ReserverPercent,默认为堆的10%)
  • 更早的回收垃圾(减少-XX:InitiatingHeapOccupacyPercent,老年代达到该值就会触发Mixed GC,默认为45%)
  • 增加并发阶段使用的线程数(增大-XX:ConcGCThreads)

(5).特点

  • 作用在整个堆
  • 停顿时间可控
  • 使用复制算法
  • 无内存碎片

10.如何选择垃圾收集器
(1).关注的需求

  • 吞吐量(Parallel Scavenge和Parallel Old)
  • 响应时间(JDK8的话,内存小于等于6G的话使用CMS,大于6G的话使用G1)

(2).JDK版本

  • JDK9废弃CMS垃圾回收器
  • JDK6才开始使用G1垃圾回收器