JVM学习-垃圾回收器

GC分类与性能指标

垃圾回收器分类

  • 按线程数分,可以分为串行垃圾回收器和并行垃圾回收器
  • 按工作模式分,可以分为并发式垃圾回收器和独占式垃圾回收器
  • 按碎片处理方式分,可分为压缩式垃圾回收器和非压缩式垃圾回收器
  • 按工作的内存区间分,可分为年轻代垃圾回收器和老年代垃圾回收器

垃圾回收器的性能指标

  • 吞吐量:运行用户代码的时间占总运行时间的比例
  • 垃圾收集开销:吞吐量的补数,垃圾收集所用时间与总运行时间的比例
  • 暂停时间:执行垃圾收集时,程序的工作线程被暂停的时间
  • 手机频率:相对于应用程序的执行,收集操作发生的频率
  • 内存占用:Java堆区所占的内存大小
  • 快速:一个对象从诞生到被回收所经历的时间

吞吐量、暂停时间、内存占用三者共同构成一个“不可能三角”,一款优秀的收集器通常最多同时满足其中的两项

吞吐量与暂停时间对比

  • 吞吐量就是CPU用于运行用户代码的时间与CPU总消耗时间的比值,即 吞吐量 = 运行用户代码时间 / (用户代码时间 + 垃圾收集时间)
例如:虚拟机总共运行了100分钟,其中垃圾收集花费1分钟,那么吞吐量就是99%
  • 暂停时间是指一个时间段内应用程序线程暂停,让GC线程执行的状态
例如:GC期间100毫秒的暂停时间意味着在这100毫秒期间内没有应用程序线程是活动的
  • 高吞吐量和低暂停时间是相互矛盾的。
如果选择吞吐量优先,必然需要降低内存回收的频率,这样会导致GC需要更长的暂停时间来执行内存回收
如选择低延迟优先,为了每次降低执行内存回收的暂停时间,只能频繁执行内存回收,这样会导致程序吞吐量下降
  • 当前标准:在最大吞吐量有限的情况下,降低停顿时间

不同的垃圾回收器概述

  • 串行回收器:Serial、Serial Old
  • 并行回收器:ParNew、Parallel Scavenge、Parallel Old
  • 并发回收器:CMS、G1

由于Java的使用场景很多,移动端、服务端,所以针对不同场景,提供不同的垃圾收集器,提高垃圾收集的性能,所以没有最好的垃圾收集器,只有根据具体场景,选择最适合的收集器

Serial回收器:串行回收

  • Serial 收集器作为HotSpot中Client模式下的默认新生代垃圾收集器
  • Serial 收集器采用复制算法、串行回收和“Stop-the-World”机制的方式执行内存回收
  • 除了年轻代之外,Serial 收集器还提供用于执行老年代垃圾收集的Serial Old 收集器。Serial Old 收集器同样也采用了串行回收和“Stop-the-World”机制,只不过内存回收算法使用的是标记-压缩算法
优势:简单而高效(与其他收集器的单线程相比),对于限定单个CPU的环境来说,Serial 收集器由于没有
线程交互的开销,专心做垃圾收集自然可以获得最高的单线程收集效率

在HotSpot虚拟机中,使用 -XX:+UseSerialGC 参数可以指定年轻代和老年代都使用串行收集器,等价于
新生代用 Serial GC,且老年代用 Serial Old GC

总结

  • Serial 收集器是一个单线程收集器,它不仅仅只会使用一个CPU或者一条收集线程去完成垃圾收集工作,更重要的是在它进行垃圾手机时,必须暂停其他所有的工作线程,直到它收集结束(Stop The Word)
  • 对于交互较强的应用而言,这种垃圾收集器是不能接受的。一般在Java web应用程序中是不会采用串行垃圾收集器的

ParNew回收器:并行回收

  • 如果说Serial GC是年轻代中的单线程垃圾收集器,那么 ParNew 收集器则是 Serial 收集器的多线程版本
  • ParNew 收集器除了采用并行回收的方式执行内存回收外,两款垃圾收集器之间几乎没有任何区别。ParNew收集器在年轻代中同样也是采用复制算法、“Stop-The-World”机制
  • ParNew是很多JVM运行在Server模式下新生代的默认垃圾收集器

Serial 对比 ParNew

  • ParNew 收集器运行在多CPU的环境下,由于可以充分利用多CPU、多核心等物理硬件资源优势,可以更快速地完成垃圾收集,提升程序的吞吐量
  • 在单个 CPU 的环境下,ParNew收集器不比Serial收集器更高效。虽然Serial收集器是基于串行回收,但是由于CPU不需要频繁地做任务切换,因此可以有效避免多线程交互过程中产生的一些额外开销
  • 除Serial外,目前只有ParNew GC能与CMS收集器配合工作

总结

  • 对于新生代,回收次数频繁,使用并行方式高效
  • 对于老年代,回收次数少,使用串行方式节省资源。(CPU并行需要切换线程,串行可以省去切换线程的资源)

Parallel回收器:吞吐量优先

  • HotSpot的年轻代中除了拥有ParNew收集器是基于并行回收的以外,Parallel Scavenge收集器同样也采用了复制算法、并行回收和“Stop-the-World”机制
  • 高吞吐量则可以高效的利用 CPU 时间,尽快完成程序的运算任务,主要适合在后台运算而不需要太多交互的任务。因此,常见在服务器环境中使用。例如,需执行批量处理、订单处理、工资支付、科学计算的应用程序
  • Parallel 收集器在JDK1.6时提供了用于执行老年代垃圾收集的Parallel Old收集器,用来替代老年代的Serial Old收集器
  • Parallel Old收集器采用标记-压缩算法,但同样也是基于并行回收和“Sotp-the-World”机制

Parallel 对比 ParNew

  • 和ParNew收集器不同,Parallel Scavenge收集器的目标则是达到一个可控制的吞吐量,他也被称为吞吐量优先的垃圾收集器
  • 自适应调节策略也是Parallel Scavenge与ParNew一个重要区别

总结

  • 在程序吞吐量优先的场景中,Parallel 收集器和 Parallel Old收集器的组合,在Server模式下的内存回收性能很不错
  • 在Java8中,默认是此垃圾收集器

CMS回收器:低延迟

  • JDK1.5时期,HotSpot推出了一款在强交互应用中几乎可认为有划时代意义的垃圾收集器:CMS(Concurrent-Mark-Sweep)收集器,这款收集器是HotSpot虚拟机中第一款真正意义上的并发收集器,它第一次实现了让垃圾收集线程与用户线程同时工作
  • CMS收集器的关注点是尽可能缩短垃圾收集时用户线程的停顿时间。停顿时间越短(低延迟)就越适合与用户交互的程序,提升用户体验
  • CMS采用标记-清除算法,并且也会"Stop-the-World’
  • CMS作为老年代的收集器,无法与Parallel Scavenge配合工作,所以新生代只能选择ParNew或者Serial收集器中的一个

CMS的工作流程:初始标记阶段 - 并发标记阶段 - 重新标记阶段 - 并发清除阶段

初始标记阶段:标记出GC Roots能直接关联到的对象。一旦标记完成就会恢复线程。由于关联对象较小,所以速度非常快

并发标记阶段:从GC Roots的直接关联对象开始遍历整个对象的过程,耗时较长但不需停顿用户线程,可与垃圾收集线程并行

重新标记阶段:并发标记时,工作线程与垃圾收集线程同时交叉运行,为修正并发标记时,因用户程序继续运作而导致标记
产生变动的那一部分对象的标记记录,这个阶段停顿时间通常比初始标记阶段稍长,但远比并发标记阶段的时间短

并发清除阶段:清理删除掉标记阶段判断已经死亡的对象,释放内存空间。由于不需移动存活对象,所以也可与用户线程并发执行

CMS的优点:

  • 并发收集
  • 低延迟

CMS的弊端:

  • 由于采用标记清除算法,所以会产生内存碎片
  • CMS收集器对CPU资源非常敏感。并发时,虽不会导致用户停顿,但因为占用部分线程,总吞吐量会降低
  • CMS是用户去无法处理浮动垃圾

G1回收器:区域化分代式

  • 随着应用程序所应对的业务越来越庞大、复杂,用户越来越多,没有GC就不能保证程序正常进行,而经常造成STW的GC又跟不上实际需求,所以Java7之后引入了G1收集器.主要针对配备多核CPU及大容量内存的机器
  • 是为了适应现在不断扩大的内存和不断增加的处理数量,以极高概率满足GC停顿时间的同时,兼具高吞吐量的性能特征。是JDK 9以后默认的垃圾收集器
  • G1的目标是在延迟可控的情况下获得尽可能高的吞吐量,所以称之为全功能收集器

为什么名字叫做Garbage First(G1)呢?

  • 因为G1是一个并行回收器,它把堆内存分割为很多不相关的区域(Region),物理上是不连续的。使用不同的Region来表示Eden、幸存者0区、幸存者1区,老年代等
  • G1 GC有计划地避免在整个Java堆中进行全区域的垃圾收集。G1跟踪各个Region里面垃圾堆积的价值大小(回收所需的时间和所获得的的空间大小),在后台维护一个优先列表,每次根据允许的手机时间,有限回收价值最大的Rdgion
  • 由于这种方式的侧重点在于回收垃圾最大量的区间(Region),所以G1就称之为:垃圾优先(Garbage First)

G1回收器的特点(优势)

  • 并行与并发
并行性:G1在回收期间,可以有多个GC线程同时工作,有效利用多核计算能力
并发性:G1拥有与应用程序交替执行能能力,部分工作可与应用线程同时执行,一般来说,不会发生完全阻塞的情况
  • 分代收集
分代上看,G1属于分代型垃圾回收器,会区分年轻代与老年代,年轻代依然有Eden区和S区,但从堆的结构上看,
它不要求整个Eden区、年轻代或者老年代都是连续的,也不坚持固定大小和固定数量

将堆空间分为若干个区域(Region),这些区域中包含了逻辑上的年轻代和老年代

和之前的各类回收器不同,它同时兼顾年轻代和老年代。对比其他回收器,或者工作在年轻代,或者工作在老年代
  • 空间整合
CMS收集器:“标记-清除”算法、内存碎片、若干次GC后进行一次碎片处理

G1收集器:将内存划分为一个个的Region。内存的回收是以region作为基本单位的。Region之间是复制算法,但整体上可
看作是标记-压缩算法。这两种算法都可避免内存碎片。这种特性利于程序长时间运行,分配大对象时不会无法找到连续内
存空间而提前触发下一次GC。尤其是当Java堆非常大的时候,G1的优势更加明显
  • 可预测的停顿时间模型
由于分区的原因,G1可选取部分区域进行内存回收,缩小了回收范围,因此对于全局停顿情况也能较好控制

G1每次根据允许的手机时间,优先回收价值最大的Region。保证了G1在有限时间可以获取尽可能高的收集效率

相比于CMS GC,G1未必能做到CMS在最好情况下的延时停顿,但是最差情况要好很多

G1回收器的缺点

  • 相较于CMS,G1还不具备全方位、压倒性优势,如在用户程序运行过程中,G1无论是为了垃圾收集产生的内存占用还是程序运行时的额外执行负载都要比CMS高
  • 从经验上来说,在小内存应用上CMS的表现大概率会优于G1,而G1在大内存应用上显现其优势。平衡点在6GB-8GB之间

G1回收器的常见步骤

G1的设计原则就是简化JVM性能调优,开发人员只需要简单的三步即可完成调优

  • 开启G1垃圾收集器
  • 设置堆的最大内存
  • 设置最大的停顿时间

G1中提供了三种垃圾回收模式:YoungGC、Mixed GC和Full GC,在不同的条件下触发

G1回收器垃圾回收过程

主要包括如下三个环节:

  • 年轻代GC(Young GC)
应用程序分配内存,当Eden区开始回收过程:G1的年轻代收集阶段是一个并行的独占式收集器。年轻代收集
时,G1 GC暂停所有应用程序线程,启动多线程执行回收,然后从年轻代区间移动存活对象到Survivor区间或
者老年代区间,也有可能两个区间都涉及
  • 老年代并发标记过程(Concurrent Marking)
当堆内存使用达到一定值(默认45%)时,开始老年代并发标记过程
  • 混合回收(Mixed GC)
标记完成开始混合回收,这一期间,G1 GC从年轻区间移动存活对象到空闲区间,这些空闲区间成了老年代的
一部分。和年轻代不同,老年代的G1回收器和其他GC不同,G1的老年代回收器不需要整个老年代被回收,一
次只需扫描/回收一小部分老年代的Region就可以。同时,这个老年代的Region是和年轻代一起被回收的

如果需要,单线程、独占式、高强度的Full GC还是继续存在的。它针对GC的评估失败提供了一种失败保护机制,即强力回收

垃圾回收器总结

垃圾收集器分类作用位置使用算法特点适用场景
Serial串行回收新生代复制算法响应速度适用于单CPU环境下的client模式
ParNew并行回收新生代复制算法响应速度多CPU环境Server模式下与CMS配合使用
Parallel并行回收新生代复制算法吞吐量适用于后台运算但不需太多交互
Serial Old串行回收老年代标记压缩响应速度适用于单CPU环境下的Client模式
Parallel Old并行回收老年代标记压缩吞吐量适用于后台运算但不需太多交互
CMS并行回收老年代标记清除响应速度适用于适用于互联网或B/S业务
G1并发并行新生代老年代复制、标记压缩响应速度适用于面向服务端应用

GC的发展阶段

Serial(单CPU) => Parallel(并行) => CMS(并发) => G1 => ZGC

评估GC的性能指标

  • 吞吐量:运行用户代码的时间占总时间的比例(总运行时间:程序运行时间+内存回收时间)
  • 垃圾收集开销:吞吐量的补数,垃圾收集所用时间与总运行时间的比例
  • 暂停时间:执行垃圾收集时,程序的工作线程被暂停的时间
  • 收集频率 :相对于应用程序的执行,收集操作发生的频率
  • 内存占用:Java堆区所占得内存大小
  • 快速:一个对象从诞生到被回收所经历的时间

收集器的选择

如何选择垃圾收集器

1、优先调整堆的大小让JVM自适应完成
2、如果内存小于100M,使用串行收集器
3、如果是单核、单机程序,并且没有停顿时间的要求,串行收集器
4、多CPU,需高吞吐量、允许STW超过1秒,选择并行或JVM自适应完成
5、多CPU,追求低停顿、快速响应,使用并发收集器(官方推荐G1,性能高)

想要最小化地使用内存和并行开销,选择Serial GC;
想要最大化应用程序的吞吐量,选择Parallel GC;
想要最小化GC的中断或停顿时间,选择CMS GC;

小结

  • 没有最好的收集器,更没有万能的收集器
  • 调优永远是针对特定场景、特定需求,不存在一劳永逸的收集器

GC日志分析

垃圾回收器的新发展

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值