深入剖析JVM垃圾收集器

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

文章目录

前言

参考资料《深入理解Java虚拟机》

垃圾收集器是GC的实践者目前常用经典的垃圾收集器有7款如下图所示
在这里插入图片描述
收集器之间的连线说明可以搭配使用JDK9标识代表在该版本官方已经不支持配合使用了

接下来逐一介绍这几款垃圾收集器。

1、新生代垃圾收集器

1.1、Serial

顾名思义单线程的垃圾收集器这里的单线程不仅仅说明它只使用一个GC线程进行垃圾收集更重要的是它进行GC时其他的工作线程必须暂停直到GC线程工作结束这种现象就是大名鼎鼎的STWStop The World这种现象对很多应用来说是不可接受的

Serial/Serial Old收集器运行示意图
在这里插入图片描述

1.2、ParNew

ParNew收集器实质是Serial收集器的多线程并行版本

可以认为ParNew除了同时使用多线程进行GC外其余行为和Serial收集器完全一致控制参数、STW、回收策略等ParNew/Serial Old运行示意图如下
在这里插入图片描述
CMS出现巩固了ParNew的地位因为新生代只有Serial和ParNew能与CMS配合使用。不过好景不长更先进的G1全堆垃圾收集器干掉了这对苦命鸳鸯从JDK9开始官方希望G1彻底取代这对组合。

ParNew在单核CPU中比Serial效果更差因为需要频繁的上下文切换ParNew默认开启的GC线程数与CPU核数相同可以使用-XX:ParallelGCThreads参数限制GC的线程数。

1.3、Parallel Scavenge

与前两款新生代收集器一样Parallel Scavenge同样采用标记-复制算法该收集器还支持多个GC线程并行看起来和ParNew没啥区别接下来我们探讨一下它到底有什么特别之处。

该收集器专注于吞吐量吞吐量 = CPU运行用户代码时间 / 运行用户代码时间 + 运行GC时间高吞吐量可以最高效率利用CPU资源尽快完成程序运算任务主要适合在后台运算而不需要太多交互的分析任务。

该收集器通过两个参数精确控制吞吐量

  1. -XX:MaxGCPauseMillis控制最大垃圾收集停顿时间通过牺牲新生代空间和吞吐量实现
  2. -XX:GCTimeRatio直接设置吞吐量大小默认值99尽可能保证应用程序执行时间为收集器执行时间的99倍也就是收集器的时间消耗不超过总运行时间的1%

相比于ParNew该收集器最重要的特性自适应调节策略通过参数-XX:+UseAdaptiveSizePolicy控制参数激活后就不需要手动指定新生代、Eden和Survivor区比例、晋升老年代对象大小等细节参数了JVM会根据当前系统的运行情况收集性能监控信息动态调整这些参数提供最合适的停顿时间或最大的吞吐量。

2、老年代垃圾收集器

2.1、Serial Old

和Serial基本一致也是单线程垃圾收集器只不过Serial使用于新生代采用复制算法Serial使用于老年代采用标记-整理算法这里就不过多介绍了运行原理如图
在这里插入图片描述

2.2、Parallel Old

可以认为它是Parallel Scavenge收集器的老年代版本这里也不做过多介绍了大致是一样的在注重吞吐量或CPU资源稀缺的场合可以有效考虑使用Parallel Scavenge + Parallel Old组合运行示意图如下

在这里插入图片描述

2.3、CMSConcurrent Mark Sweep

以获取最短回收停顿时间为目标的收集器。

相比于两外两个收集器CMS采用的是标记-清除算法它的运行过程分为四个步骤其中初始标记重新标记需要STW

  1. 初始标记仅仅标记GC Roots能直接关联到的对象速度很快
  2. 并发标记从GC Roots直接关联对象开始遍历整个对象图的过程过程耗时较长但不需要停顿用户线程
  3. 重新标记为了修正并发标记阶段因用户线程继续运行而导致标记产生变动那部分对象的标记记录停顿时间大于初始标记小于并发标记
  4. 并发清除清除标记阶段判断的已经死亡对象该阶段可以与用户线程同时并行

在这里插入图片描述

CMS有三个明显的缺点

  1. CMS对CPU资源十分敏感
    虽然CMS不会造成用户线程停顿但是会因为占用了一部分线程而导致应用程序变慢降低总吞吐量
  2. CMS无法处理浮动垃圾
    有可能出现Con-current Mode Failure失败进而导致另一次STW的Full GC产生。在CMS并发标记和并发清理阶段用户线程还是在运行自然就会有新的垃圾对象产生这部分对象还是在标记过程结束后产生的CMS无法在本次GC过程中处理掉它们只能等到下一次清除所以CMS不能像其他收集器那样等到老年代几乎填满在收集必须预留一部分空间以供并发收集时程序运作使用。可以通过参数-XX:CMSInitiatingOccu-pancyFraction控制CMS触发百分比设置太高容易造成大量的并发失败产生设置太低会导致频繁进行GC
  3. CMS采用标记-清除算法所以会有内存碎片问题

3、全堆垃圾收集器

3.1、Garbage FirstG1

G1开创了面向局部收集设计思路和基于Region的内存布局形式。

G1把连续的堆内存划分为多个大小相等的独立区域Region每个Region都可以根据需要扮演成Eden、Survivor、老年代空间针对不同角色的Region采用不同的策略去处理获取很好的收集结果。

Region中有一类特殊的Humongous区域专门用于存储大对象。
G1认为只要大小超过一个Region一半的对象皆为大对象Region大小可以通过参数-XX:G1HeapRegionSize设定范围为1~32MB。对于超过了整个Region容量的超级大对象会被存放在N个连续的Humongous Region中G1将其看作老年代的一部分。

G1每次GC的内存空间都是Region大小的整数倍它会跟踪每个Region垃圾价值大小价值即回收所获得的空间大小以及回收所需的时间经验值然后在后台维护一个优先级列表优先回收收益最大的那些Region。

在这里插入图片描述

G1收集器的运作过程大致可划分为以下四个步骤

  1. 初始标记仅仅标记GC Roots直接关联的对象并且修改TAMS指针让下个阶段用户线程并发运行时正确地在可用的Region中分配新对象耗时很短。
  2. 并发标记从GC Root开始对堆中对象进行可达性分析找到要回收的对象可与用户线程并发执行耗时较长。
  3. 最终标记用户线程短暂暂停用于处理并发阶段结束后遗留下来的最后那少量的SATB记录。
  4. 筛选回收对各个Region根据回收价值和成本进行排序根据用户期望停顿时间制定回收计划自由选择任意多个Region作为回收集然后把决定回收的部分Region存活对象复制到空的Region中再清理掉整个旧Region全部空间。这里涉及对象的移动必须是暂停用户线程多条GC线程并行完成。

在这里插入图片描述

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6