5.垃圾收集器

一、垃圾回收器分类

image.png

新生代垃圾收集器:Serial 、 ParNew 、Parallel Scavenge
老年代垃圾收集器:Serial Old 、 Parallel Old 、CMS
整理收集器:G1

垃圾回收器组合关系

image.png

  • JDK7、8中默认使用组合是: Parallel Scavenge GC 、ParallelOld GC
  • JDK9默认使用G1为垃圾收集器
  • JDK14 弃用了: Parallel Scavenge GC 、Parallel OldGC;移除了 CMS GC

GC性能指标

  • 吞吐量:即CPU用于运行用户代码的时间与CPU总消耗时间的比值(吞吐量 = 运行用户代码时间 / ( 运行用户代码时间 + 垃圾收集时间 ))。例如:虚拟机共运行100分钟,垃圾收集器花掉1钟,那么吞吐量就是99%
  • 暂停时间:执行垃圾回收时,程序的工作线程被暂停的时间

二、Serial垃圾收集器

串行。针对新生代;采用标记-复制算法; 进行垃圾收集时,必须暂停所有工作线程,直到完成;

  • 使用方式:-XX:+UseSerialGC

三、ParNew垃圾收集器

并发。针对新生代;采用标记-复制算法。ParNew收集器实质上是Serial收集器的多线程并行版本, 除了同时使用多条线程进行垃圾收集之外都一样。

  • 使用方式: 使用方式:-XX:+UseParNewGC

四、Parallel Scavenge垃圾收集器

并行(单核无并行)。新生代收集器;采用标记-复制算法。是1.8中默认的收集器;吞吐量优先。

特点
  • Parallel Scavenge收集器的目标是达到一个可控制的吞吐量(Throughput);
    吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间) (虚拟机总共运行100分钟,垃圾收集时间为1分钟,那么吞吐量就是99%)
  • 自适应调节策略,自动指定年轻代、Eden、Suvisor区的比例。
适用场景

适合后台运算,交互不多的任务,如批量处理,订单处理,科学计算等。

在学生端的论坛项目中使用这种垃圾收集器,其项目访问刷新频率较低,但是有
很多后台定时的计算任务,适合使用这种垃圾收集器

参数设置:

使用方式:-XX:+UseParallelGC
吞吐量大小-XX:GCTimeRatio

-XX: GCTimeRatio参数的值则应当是一个大于0小于100的整数, 也就是垃圾收集时间占总时
间的 比率, 相当于吞吐量的倒数。 假设GCTimeRatio的值为n,那么系统将花费不超过1/(1+n)
的时间用于垃圾收集。譬如把此 参数设置为19, 那允许的最大垃圾收集时间就占总时间的5%
(即1/(1+19)) , 默认值为99, 即允许最大1%(即 1/(1+99)) 的垃圾收集时间

最大垃圾收集停顿时间:-XX:MaxGCPauseMillis

-XX: MaxGCPauseMillis参数允许的值是一个大于0的毫秒数, 收集器将尽力保证内存回收
花费的 时间不超过用户设定值。 不过大家不要异想天开地认为如果把这个参数的值设置得更
小一点就能使得 系统的垃圾收集速度变得更快, 垃圾收集停顿时间缩短是以牺牲吞吐量和新
生代空间为代价换取的: 系统把新生代调得小一些, 收集300MB新生代肯定比收集500MB
快, 但这也直接导致垃圾收集发生得 更频繁, 原来10秒收集一次、 每次停顿100毫秒, 
现在变成5秒收集一次、 每次停顿70毫秒。 停顿时间 的确在下降, 但吞吐量也降下来了。

五、 Serial Old垃圾收集器

串行。针对老年代;采用标记-整理算法;
使用方式:-XX:+UseSerialGC

六、 Parallel Old垃圾收集器

并行。是Parallel Scavenge收集器的老年代版本, 支持多线程并发收集, 基于标记-整理算法实现。

应用场景
  • JDK1.6及之后用来代替老年代的Serial Old收集器;
  • 特别是在Server模式,多CPU的情况下;
  • 这样在注重吞吐量以及CPU资源敏感的场景,就有了Parallel Scavenge加Parallel Old收集器的"给力"应用组合;

七、CMS 垃圾收集器

并发。老年代的垃圾回收器。是以获取最短垃圾收集停顿时间为目标的收集器。使用的算法是标记-清除算法

适用场景

目前很大一部分的java应用几种在互联网的B/S系统服务器上,这类应用尤其注重服务器的响应速度,系统停顿时间最短,给用户带来良好的体验。

在管理端和学生端的交互性比较强的项目中可以使用这种垃圾回收

参数设置:XX:+UseConcMarkSweepGC

收集过程

1) 初始标记
2) 并发标记
3) 重新标记
4) 并发清除

- 初始标记(Initial-Mark)阶段:这个阶段程序所有的工作线程都将会因为"Stop-the-Wold"机制
而出现短暂的的暂停,这个阶段的主要任务标记处GC Roots 能够关联到的对象.一旦标记完成后
就恢复之前被暂停的的所有应用。 由于直接关联对象比较小,所以这里的操作速度非常快。
- 并发标记(Concurrent-Mark)阶段:从GC Roots的直接关联对象开始遍历整个对象图的过程,
这个过程耗时较长,但是不需要暂停用户线程, 用户线程可以与垃圾回收器一起运行。
- 重新标记(Remark)阶段:由于并发标记阶段,程序的工作线程会和垃圾收集线程同时运行
或者交叉运行,因此,为了修正并发标记期间因为用户继续运行而导致标记产生变动的那一
部分对象的标记记录,这个阶段的停顿时间通常比初始标记阶段长一些,但也远比并发标记
阶段时间短。
- 清除并发(Concurrent-Sweep)阶段: 此阶段清理删除掉标记判断已经死亡的对象,并释放
内存空间。由于不需要移动存活对象,所以这个阶段可以与用户线程同时并发运行。
三色标记
  • 白色:尚未访问过。
  • 黑色:本对象已访问过,而且本对象 引用到 的其他对象 也全部访问过了。
  • 灰色:本对象已访问过,但是本对象 引用到 的其他对象尚未全部访问完。全部访问后,会转换为黑色。
注意:在并发标记的时候可能会出现多标和漏标的情况,多标会产生浮动垃圾,漏标会将引用中
的对象清除会导致程序出错,需要在重新标记的时候(会stop the world)做出修改防止这种情况出现
缺点

1.CMS收集器对CPU资源非常敏感。在并发阶段,它虽然不会导致用户线程停顿,但是会因为占用、了一部分线程而导致应用程序变慢,总吞吐量会降低。是当处理器核心数量不足四个时, CMS对用户程序的影响就可能变得很大。
2.CMS收集器无法处理浮动垃圾,可能出现"Concurrent Mode Failure"失败而导致另一次Full GC的产生。
3.空间碎片:CMS是一款基于标记-清除算法实现的收集器,所有会有空间碎片的现象
concurrent mode failure是什么?
  CMS垃圾收集器特有的错误,CMS的垃圾清理和引用线程是并行进行的,如果在并行清理的过程中老年代的空间不足以容纳应用产生的垃圾(也就是老年代正在清理,从年轻代晋升了新的对象,或者直接分配大对象年轻代放不下导致直接在老年代生成,这时候老年代也放不下),则会抛出“concurrent mode failure”。

八、G1垃圾收集器

Garbage First是一款面向服务端应用的垃圾收集器,主要针对配备多核CPU及大容量内存的机器,以极高概率满足GC停顿时间的同时,还兼具高吞吐量的性能特征。

G1收集器特点
  1. G1把内存划分为多个独立的区域Region
  2. G1仍然保留分代思想,保留了新生代和老年代,但他们不再是物理隔离,而是一部分Region的集合
  3. G1能够充分利用多CPU、多核环境硬件优势,尽量缩短STW
  4. G1整体整体采用标记整理算法,局部是采用复制算法,不会产生内存碎片
  5. G1的停顿可预测,能够明确指定在一个时间段内,消耗在垃圾收集上的时间不超过设置时间
  6. G1跟踪各个Region里面垃圾的价值大小,会维护一个优先列表,每次根据允许的时间来回收价值最大的区域,从而保证在有限事件内高效的收集垃圾
Region

G1不再坚持固定大小以及固定数量的 分代区域划分, 而是把连续的Java堆划分为多个独立区域(Region) , 每一个Region都可以根据需要, 扮演新生代的Eden空间、 Survivor空间, 或者老年代空间。Region是G1回收器一次回收的最小单元。即每一次回收都是回收N个Region。

image.png

将整个堆空间细分为若干个小的区域。
  • ①使用G1收集器时,它将整个Java堆划分成约2048个大小相同的独立Region块,每个Region块大小根据堆空间的实际大小而定,为2的N次幂,即1MB, 2MB, 4MB, 8MB, 16MB,32MB。
  • ② 虽然还保留有新生代和老年代的概念,但新生代和老年代不再是物理隔离的了,它们都是一部分Region (不需要连续)的集合。通过Region的动态分配方式实现逻辑上的连续。
  • ③ G1垃圾收集器还增加了一种新的内存区域,叫做Humongous内存区域,如图中的H块。主要用于存储大对象,如果超过1 .5个region,就放到H。一般被视为老年代.
卡片 Card

在每个分区内部又被分成了若干大小为512 Byte卡片(Card),标识堆内存最小可用粒度所有分区的卡片将会记录在全局卡片表(Global Card Table)中,分配的对象会占用物理上连续的若干个卡片,当查找对分区内对象的引用时便可通过记录卡片来查找该引用对象(见RSet)。每次对内存的回收,都是对指定分区的卡片进行处理。
G1对内存的使用以分区(Region)为单位,而对对象的分配则以卡片(Card)为单位。

G1的gc过程

G1提供了两种GC模式,Young GC和Mixed GC,两种均是完全Stop The World的。

  • Young GC:对年轻代的gc
  • Mixed GC:对年轻代和老年的gc
在G1 GC垃圾回收的过程一个有四个阶段:
  • 初始标记 :和CMS一样
    只标记GC Roots直接关联的对象
  • 并发标记 :进行GC Roots Traceing过程
  • 最终标记 :修正并发标记期间,因程序运行导致发生变化的那一部分对象
  • 筛选回收 :根据时间来进行价值最大化收集。把一部分region的活对象拷贝到空Region里面去,然后回收原本的Region空间,该阶段是STW(stop-the-world)的。整理堆分区,为混合收集周期识别回收收益高(基于释放空间和暂 停目标)的老年代分区集合;

随着老年代内存增长,当到达IHOP阈值-XX:InitiatingHeapOccupancyPercent(老年代占整堆比,默认45%)时,G1开始着手准备收集老年代空间。首先经历并发标记周期,识别出高收益的老年代分区,前文已述。但随后G1并不会马上开始一次混合收集,而是让应用线程先运行一段时间,等待触发一次年轻代收集。在这次STW中,G1将保准整理混合收集周期。接着再次让应用线程运行,当接下来的几次年轻代收集时,将会有老年代分区加入到CSet中,即触发混合收集,这些连续多次的混合收集称为混合收集周期

你可能感兴趣的:(5.垃圾收集器)