GC-分代收集器
GC收集器介绍
十款GC收集器
上图中共有十款GC收集器,它们可以根据回收时的属性分为分代和分区两种类型:
-
分代收集器:Serial、ParNew、Parallel Scavenge、CMS、Serial Old(MSC)、Parallel Old
-
分区收集器:G1、ZGC、Shenandoah
GC收集器中的名词解释
在GC收集器中存在一些经常出现的名词,这些名词也是在认识GC收集器之前不得不了解的,如:串行回收、并行回收、独占执行、并发执行、吞吐量、停顿时间、吞吐量优先、响应时间优先等。
串行、并行与独占、并发
- 串行Serial收集:所有用户线程停止,单条GC线程回收堆的情况被称为串行回收。
- 并行Parallel收集:所有用户线程停止,多条GC线程回收堆的情况(需多核CPU支持)。
- 独占Monopoly执行:这里是指GC工作时,GC线程会抢占所有资源执行,整个应用程序会被停止。
- 并发Concurrent执行:这里的并发是指用户线程和GC线程同时(交替)执行的情况,不会停下某类线程。
吞吐量
吞吐量是性能优化中的一个重要指标,它是指CPU用于执行用户代码的时间与CPU总耗时的比值,在Java中,吞吐量的计算公式为:
吞吐量 = 用户代码执行总时长 /(用户代码执行总时长 + 垃圾回收总时长)。
如JVM在线上执行了100min,其中执行用户代码花费了99min,垃圾回收总用时1min,那么吞吐量则为99min/(99min+1min)=99%。
停顿时间
停顿时间是指GC收集器在工作时,所有用户线程(整个应用程序)的暂停时间。对于独占类的GC收集器而言,停顿时间会比较长。而对于并发类的GC收集器来说,因为GC线程和用户线程是交替执行的,所以程序的停顿时间会缩短,但总体GC效率不如独占GC收集器,因此系统的吞吐量会降低。
基于独占收集器和并发收集器的特性而言,就牵扯出了两个调优时的新名词:吞吐量优先与响应时间优先。 相对而言,在设计系统架构选择GC收集器或进行调优时,最终都是在追求更高的吞吐量以及更短的响应时间。
-
吞吐量优先:为了确保程序的更高吞吐,允许GC发生时出现长时间暂停。
-
响应时间优先:为了确保用户更好的体验,可以牺牲一定的吞吐量换取更快的响应速度,发生GC时暂停时间越短越好。
分代收集器
● 新生代收集器:Serial、ParNew、Parallel Scavenge
● 年老代收集器:CMS、Serial Old(MSC)、Parallel Old
新生代收集器
前面提到过新生代收集器主要包含Serial、ParNew、Parallel Scavenge,首先来看看作用于新生代的Serial收集器。
Serial收集器(单线程)
Serial是最原始的新生代收集器,同时它属于单线程的GC收集器,所以也被称为串行收集器。顾名思义,它在执行GC工作时,是以单线程运行的,并且该收集器在发生GC时,会产生STW,也就是会停止所有用户线程。但正由于会停止其他用户线程,所以在执行GC时并不会出现线程间的切换。因此,在单颗CPU的机器上,它的清理效率非常高。
收集动作:串行GC,单线程。
采用算法:复制算法。
STW:GC过程在STW中执行。
GC发生时,执行过程如下:
GC过程中是需要全程发生在STW中的,所以基于系统层面来说,对用户体验感欠佳。
ParNew收集器(多线程)
ParNew收集器是基于Serial收集器的演进版,从严格意义上来看,它可以被称为Serial收集器的多线程版本,同样是作用于新生代区域的收集器。在整个实现上,除开GC收集阶段会使用多条线程回收外,其他实现几乎与Serial收集器大致相同
收集动作:并行GC,多线程。
采用算法:复制算法。
STW:GC过程发生在STW中,采用多线程回收。
GC发生时,执行过程如下:
与Serial唯一的不同点就在于使用了多线程,所以GC发生时仍旧会造成程序停顿。但也因为使用了多线程回收,因此能够在很大程度上缩短系统的停顿时间,从而能够带来比Serial更好的用户体验。更关注吞吐量
Parallel Scavenge收集器(多线程)
Parallel Scavenge同样是一款作用于新生代的多线程GC收集器,但与ParNew收集器不同的是:ParNew通过控制GC线程数量来缩短程序暂停时间,更关心程序的响应时间,而Parallel Scavenge更关心的是程序运行的吞吐量
收集动作:并行GC,多线程。
采用算法:复制算法。
STW:GC过程发生在STW中,采用多线程回收。
GC发生时,执行过程如下:
Parallel收集器和ParNew收集器好像并未有太大的区别。但实际上它们两者之间基于的底层GC框架完全不同,同时关注的方向也完全不同。PS收集器的目标是让程序达到一个可控制的吞吐量(Throughput),所以PS也被称为吞吐量优先的垃圾收集器
GC追求响应时间的时候必然会牺牲吞吐量,而追求吞吐量的同时必然会牺牲响应时间。
老年代GC收集器详解
年老代收集器主要有CMS、Serial Old(MSC)、Parallel Old三款,与新生代的收集器一样,同样存在单线程和多线程收集器之分,接下来我们对年老代收集器进行依次分析。
Serial Old(MSC)收集器(单线程)
Serial Old(MSC)与Serial收集器相同,同样是一款单线程串行回收的收集器,但不同的是:MSC是一款作用于年老代空间的收集器,它采用标记-整理算法对年老代空间进行回收
收集动作:串行GC,单线程。
采用算法:标记-整理算法。
STW:GC过程发生在STW中,采用单线程执行串行回收。
GC发生时,执行过程如下:
Parallel Old收集器(多线程)
Parallel Old则是Parallel Scavenge收集器的年老代版本,同样采用多线程进行并行收集,其内部采用标记-整理算法。与新生代的PS收集器相同的是:PO同样追求的是吞吐量优先。
收集动作:并行GC,多线程。
采用算法:标记-整理算法。
STW:GC过程发生在STW中,采用多线程回收。
GC发生时,执行过程如下:
Parallel Old收集器的年老代版本同样关注于吞吐量系统。
CMS收集器(多线程/并发)
CMS收集器全称为ConcurrentMarkSweep,该款回收器是GC机制中的一座里程碑,在该款收集器中首次实现了并发收集的概念,也就是不停止用户线程,GC线程与用户线程一同工作的情况。同时该款收集器追求的是最短的回收时间,属于多线程收集器,其内部采用标记-清除算法。
jkd9标记为弃用,jdk14正式移除
收集动作:并发GC,多线程并行执行
采用算法:标记-清除算法。
STW:GC过程会发生STW,但并非整个GC过程都在STW中执行,采用多线程回收。
GC发生时,执行过程如下:
CMS对比其他的GC收集器,回收过程明显复杂很多,CMS收集器的回收工作会分为四个步骤:初始标记、并发标记、重新标记以及并发清除。
在整个收集过程中,除开初始标记与重新标记阶段,其他的收集动作都是与用户线程并发执行的。因此,CMS收集器在发生GC时,造成的程序暂停是非常短暂的,对于用户体验感而言,相对比之前的收集器而言是最优者。也正由于CMS收集器并发收集、停顿延迟低的特性,所以在有些地方也被称为并发低停顿收集器。
CMS也存在几个致命的缺点:会产生且无法回收浮动垃圾、对CPU资源非常依赖、GC完成后会造成大量内存碎片。
分代GC收集器总结
分代收集器有两个指标,低延迟收集器和高吞吐收集器,根据服务自身业务需求去指定GC收集器
ParNew通过控制GC线程数量来缩短程序暂停时间,更关心程序的响应时间,而Parallel Scavenge更关心的是程序运行的吞吐量
一般而言,如果你的程序是更为关注用户体验度,那么可以采用响应速度优先的收集器工作,因为该类收集器造成的程序暂停不会很久。但如若你的程序不需要与用户有特别多的交互,如批量处理、订单处理、报表计算、科学计算等类型的后台系统,那你则可以采用吞吐量优先的收集器,因为高吞吐量可以高效率地利用CPU资源。
GC组合方案分析
- 组合一
如果你的程序追求低延迟,用户交互度较为频繁,那你可以采用ParNew + CMS组合(这也是淘宝早期的选择,但后面采用了自研JVM)。
- 组合二
如若你的程序追求高吞吐,后台计算工作较多,那么Parallel Scavenge + Parallel Old这组PS+PO的收集器会更适合你。
- 组合三
但你的程序写出来后,更多的情况下部署在单核或双核的机器时,那么最经典的Serial + Serial Old组合绝对是你的最佳选择。
我们再一次将目光聚集在这张图上,需要值得注意的是:在JDK1.8之前,可以采用虚线组合,但在JDK1.8之后,取消了上图中红线的组合,被视为弃用的收集器组合(但如果要用,也是可以用的)。到了JDK1.9时,红线组合被移除,也就代表着在1.9中无法再指定红线组合作为收集器使用。而到了后面的JDK14时,绿线组合也被弃用,同时官方也移除了CMS收集器,为了给G1铺路,使用G1代替了CMS。
三色标记算法
三色标记算法是自CMS收集器后,应用比较广泛的一种并发标记算法,它可以让JVM在发生GC时,只发生短暂的STW即可实现存活对象标记的一种算法。JVM中的CMS以及后续的不分代收集器,之所以可以做到低延迟的根本原因便在于此处。
- 白色 (White):
○ 未被访问的对象被标记为白色。
○ 白色对象是未被标记的对象,可能是垃圾。 - 灰色 (Gray):
○ 正在访问的对象被标记为灰色。
○ 灰色对象是已经被发现但还未完全处理的对象,即它们的引用还没有被完全遍历。 - 黑色 (Black):
○ 已经完全访问的对象被标记为黑色。
○ 黑色对象是已经被完全处理的对象,即它们的所有引用都已经遍历完毕。
三色标记执行过程
标记执行图
实现了三色标记算法的GC收集器,在启动时会分别创建:黑、白、灰三个集合,在最开始所有的对象都在白色集合中。
● 在GC发生时,发生短暂的STW,将所有与GcRoots直接相连的对象转入灰色集合中。
● 之后并发执行,对灰色集合中的对象进行遍历,根据可达性分析算法进行对象存活标记,当一个对象的所有成员全部被标记完成后,该对象则会被移入到黑色集合中。同时,也会将该对象中被标记的成员从白色集合移入灰色集合中。
● 不断重复上一步操作,直至灰色集合彻底没了对象为止。
● 标记完成所有对象后,再次触发STW,通过write-barrier写屏障检测对象是否有变化,如果发生了改变则重新标记,纠正并发标记期间的“误标”。
● 并发执行清除工作,将白色集合中的所有对象全部回收(因为根据GCRoots节点进行可达性分析后,所有的存活对象都会从白色集合移入到黑色集合中,所以依旧留在白色集合中的对象必然为垃圾对象,这些对象就是需要被回收的对象)。
● 最终等待清除工作完成后,代表着整个GC过程结束,再把标记复位,将所有的对象再次放入白色集合中,等待迎接下次GC的到来。
三色标记-并发标记导致的错标问题
被标记的黑色对象中,突然断开了对另一个对象的引用,导致另外一个原本已经被标记为黑色的对象突然变为了垃圾。
GC多回收几次就会被清除了
三色标记-并发执行导致的漏标问题
1一条用户线程在执行过程中,断开了一个未标记的白色对象连接,然后该对象又被一个已经标记成黑色的对象建立起了引用连接
2.白色对象断开了左侧灰色对象的引用,又与右侧的黑色对象建立了新的引用关系。
出现这种情况时,因为重新建立引用的白色对象“父节点”已经被标记黑色了,所以GC线程不会再次标记该对象以及其成员对象,所以这些白色对象会被一直停留在白色集合中。最终导致的结果就是这些依旧存在引用的存活对象会被“误判”为垃圾对象清除掉。而这种情况会直接影响到应用程序的正确性,是不可接受的。
● 采用三色标记算法的收集器又是如何具体解决漏标问题的呢?
● CMS:增量更新 + 写屏障
● G1:STAB + 写屏障
● ZGC:读屏障
写屏障是在对象引用发生变化时进行干预的技术。
当对象引用发生变化时,写屏障会通知垃圾收集器,以便垃圾收集器能够更新标记状态。
在本篇中,先对CMS解决
跨代引用
即老年代的对象引用了年轻代对象,年轻代对象引用老年代对象,在进行可达性分析扫描存活对象时,不可能从新生代一直扫描至年老代的,因为这样就会出现整堆扫描的情况,效率必然会很低。
在HotSpot虚拟机中,为了解决跨代引用的问题,会专门在内存中开辟一块小空间用于维护这些特殊的引用,从而达到让GC不必扫描整个堆空间的目的。而开辟的这块小空间则被称为记忆集、卡表。
记忆集
新生代GC时都会通过根可达算法先判断垃圾对象,之后再对非存活对象进行统一回收,但是如果有年老代对象引用了新生代对象,那么根据根可达算法的特性,年老代也会被加入扫描范围,这样下来一次新生代的GC代价太大。所以为了解决跨代引用的问题,在新生代引入了记录集的数据结构,记录从非收集区到收集区的引用指针集合,避免在通过根可达算法判断对象存活时把整个老年代加入扫描范围。
GC时,GC收集器只需通过记忆集判断出某一块非收集区域是否存在指向收集区域的指针即可,无需进行详细的根搜索过程。
年轻代发生GC时,扫描一个对象时,通过记忆集发现某个引用指向年老代对象时,此时GC线程会停止扫描这个引用,从而避免出现整堆扫描的情况。
卡表
卡表是记忆集第三种精度的实现,也是HotSpot虚拟机中记忆集的实现方式,卡表中记录中记忆集的记录精度、与堆内存区域的映射关系等。
在HotSpot中卡表是使用一个字节数组实现:CARD_TABLE[this addredd >>9]=0,数组中每个元素对应着其标识的内存区域,称为卡页,hotSpot使用的卡页大小为2^9 即512字节,也就是说内存中每连续的512字节会被当作一个卡页作为卡表的一个元素。
五、GC分代篇总结
从GC的一些基础概念,到分代收集器、各款收集器收集过程、CMS收集器及其执行过程、三色标记算法、三色标记-漏标/多标问题、YoungGC、FullGC日志解读、GC诱发原因等内容进行全面阐述。
在JVM的GC体系中,其实并不存在所谓的最好GC器,不同的场景下采用合适的GC收集器,才能在最大程度上追求最优的方案。各款GC收集器对比如下:
对技术有兴趣的同学可以加群
相关文章:

GC-分代收集器
GC收集器介绍 十款GC收集器 上图中共有十款GC收集器,它们可以根据回收时的属性分为分代和分区两种类型: 分代收集器:Serial、ParNew、Parallel Scavenge、CMS、Serial Old(MSC)、Parallel Old 分区收集器ÿ…...

C++从入门到起飞之——priority_queue(优先级队列) 全方位剖析!
🌈个人主页:秋风起,再归来~🔥系列专栏:C从入门到起飞 🔖克心守己,律己则安 目录 1、priority_queue的介绍 2、priority_queue的使用 3、priority_queue的模拟实现 3.1、仿函数的介…...

[数据集][目标检测]西红柿缺陷检测数据集VOC+YOLO格式17318张3类别
数据集格式:Pascal VOC格式YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):17318 标注数量(xml文件个数):17318 标注数量(txt文件个数):17318 标…...

【小沐学OpenGL】Ubuntu环境下glut的安装和使用
文章目录 1、简介1.1 OpenGL简介1.2 glut简介1.3 freeglut 2、glut安装2.1 命令安装glut2.2 源码安装glut 3、glut测试3.1 测试1,版本打印3.2 测试2,绘制三角形3.3 测试3,VBO绘制三角形 结语 1、简介 1.1 OpenGL简介 OpenGL作为图形界的工业…...
ROS 发行版 jazzy 加载urdf 渲染到 RVIZ2
新版启动urdf需要两个包分别为urdf_tutorial、urdf_launch 配置package.xml <exec_depend>rviz_common</exec_depend> <exec_depend>rviz_default_plugins</exec_depend> <exec_depend>rviz2</exec_depend> <exec_depend>robot…...

SpringBoot中利用EasyExcel+aop实现一个通用Excel导出功能
一、结果展示 主要功能:可以根据前端传递的参数,导出指定列、指定行 1.1 案例一 前端页面 传递参数 {"excelName": "导出用户信息1725738666946","sheetName": "导出用户信息","fieldList": [{&q…...
排序链表(归并排序)
148. 排序链表 - 力扣(LeetCode) 以O(nlogn)时间复杂度, O(1)空间复杂度 排序链表 涉及知识点: 找到链表的中间节点 2095. 删除链表的中间节点 - 力扣(LeetCode)合并有序链表 21. 合并两个有序链…...

Adobe After Effects的插件--------CC Particle World
CC Particle World是一个粒子效果器,用于在三维空间中生成和模拟各种粒子系统,包括火焰、雨、雪、爆炸、烟雾等等。它会自动随时间变化发射粒子。 本文部分参照 https://www.163.com/dy/article/IEJVDN760536FE6V.html 使用条件 使用该插件的图层需是2D图层。 我们新建一个…...

电脑硬盘数据丢失了怎么恢复?简单实用的硬盘数据找回的方法
我们的电脑使用硬盘作为存储设备来保存数据,硬盘里的数据是存储在扇区上,这些存储数据的单元则位于表面有磁性材料的旋转的盘片上。硬盘内部的磁头悬浮于高速旋转的盘片上,用于读写和检索数据。 假如我们使用电脑时不小心删除了某个文件&…...
k8s调度(pod亲和、反亲和、污点、容忍度)
pod亲和性 针对对象为Pod,目的是实现,新建Pod和目标Pod调度到一起,在同一个Node上。 示例: apiVersion: v1 kind: Pod metadata:name: testpod01labels:app: myapp01env: test1 spec:containers:- name: testpod01image: nginx:…...
智能制造核心领域:自动化、物联网、大数据分析、人工智能在现代制造业中的应用与融合
一、智能制造系统及领域 智能制造系统是一套集成的解决方案,它利用物联网(IoT)、大数据分析、人工智能(AI)、机器学习和云计算等技术,实现工厂和生产线的自动化、数据驱动和智能化。这些系统能够监控和控制…...

Android Studio 2024最新版Hello World
Android Studio 2024最新版Hello World 1. Android Studio 2024安装视频2. 创建项目Read Timed out 问题Android Studio Build Output 控制台中文乱码问题 3. 驱动管理 本文章介绍如何通过Android Studio 2024最新版创建项目, 并成功输出Hello World。 本次教程版本…...
请解释Java中的CountDownLatch和CyclicBarrier的区别和使用场景。什么是Java中的Semaphore?它如何控制并发访问?
请解释Java中的CountDownLatch和CyclicBarrier的区别和使用场景。 CountDownLatch 和 CyclicBarrier 是 Java 并发包(java.util.concurrent)中提供的两个非常有用的同步工具,它们都用于控制多个线程之间的同步,但它们的目的和使用…...

Django+Vue3前后端分离学习(五)(前端登录页面搭建)
1、如果需要使用组合式API,需要安装插件: npm install vite-plugin-vue-setup-extend --save-dev 在vite.config.js里配置: 首先导入: import VueSetupExtend from vite-plugin-vue-setup-extend 添加: 2、创建login.vue 然…...
虚拟机安装macos系统
虚拟机安装macOS系统是一个相对复杂但可行的过程,主要涉及前期准备、虚拟机软件安装、macOS镜像准备、虚拟机配置、系统安装及后续设置等多个步骤。以下是一个详细的教程,帮助您在虚拟机中成功安装macOS系统。 一、前期准备 1. 硬件要求 确保您的计算…...

AI基础 L9 Local Search II 局部搜索
Local Beam search 对于当前的所有k个状态,生成它们的所有可能后继状态。 检查生成的后继状态中是否有任何状态是解决方案。 如果所有后继状态都不是解决方案,则从所有后继状态中选择k个最佳状态。 当达到预设的迭代次数或满足某个终止条件时&#x…...

828华为云征文|使用sysbench对Mysql应用加速测评
文章目录 ❀前言❀测试环境准备❀测试工具选择❀测试工具安装❀mysql配置❀未开启Mysql加速测试❀开启Mysql加速测试❀总结 ❀前言 大家好,我是早九晚十二。 昨天有梳理一篇关于华为云最新推出的云服务器产品Flexus云服务器X。当时有说过,这次的华为云F…...
2024 年高教社杯全国大学生数学建模竞赛题目——D 题 反潜航空深弹命中概率问题的求解
2024 年高教社杯全国大学生数学建模竞赛题目 (请先阅读“ 全国大学生数学建模竞赛论文格式规范 ”) D 题 反潜航空深弹命中概率问题 应用深水炸弹(简称深弹)反潜,曾是二战时期反潜的重要手段,而随着现代军…...
【Kubernetes】常见面试题汇总(一)
目录 1.简述 etcd 及其特点? 2.简述 etcd 适应的场景? 3.简述什么是Kubernetes? 4.简述 Kubernetes和 Docker的关系? 1.简述 etcd 及其特点? (1)etcd 是Core0s 团队发起的开源项目…...

简单实用的php全新实物商城系统
免费开源电商系统,提供灵活的扩展特性、高度自动化与智能化、创新的管理模式和强大的自定义模块,让电商用户零成本拥有安全、高效、专业的移动商城。 代码是全新实物商城系统源码版。 代码下载...

TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...
基于服务器使用 apt 安装、配置 Nginx
🧾 一、查看可安装的 Nginx 版本 首先,你可以运行以下命令查看可用版本: apt-cache madison nginx-core输出示例: nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...
电脑插入多块移动硬盘后经常出现卡顿和蓝屏
当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时,可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案: 1. 检查电源供电问题 问题原因:多块移动硬盘同时运行可能导致USB接口供电不足&#x…...
生成 Git SSH 证书
🔑 1. 生成 SSH 密钥对 在终端(Windows 使用 Git Bash,Mac/Linux 使用 Terminal)执行命令: ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" 参数说明: -t rsa&#x…...
spring:实例工厂方法获取bean
spring处理使用静态工厂方法获取bean实例,也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下: 定义实例工厂类(Java代码),定义实例工厂(xml),定义调用实例工厂ÿ…...

【配置 YOLOX 用于按目录分类的图片数据集】
现在的图标点选越来越多,如何一步解决,采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集(每个目录代表一个类别,目录下是该类别的所有图片),你需要进行以下配置步骤&#x…...

网站指纹识别
网站指纹识别 网站的最基本组成:服务器(操作系统)、中间件(web容器)、脚本语言、数据厍 为什么要了解这些?举个例子:发现了一个文件读取漏洞,我们需要读/etc/passwd,如…...

DingDing机器人群消息推送
文章目录 1 新建机器人2 API文档说明3 代码编写 1 新建机器人 点击群设置 下滑到群管理的机器人,点击进入 添加机器人 选择自定义Webhook服务 点击添加 设置安全设置,详见说明文档 成功后,记录Webhook 2 API文档说明 点击设置说明 查看自…...
腾讯云V3签名
想要接入腾讯云的Api,必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口,但总是卡在签名这一步,最后放弃选择SDK,这次终于自己代码实现。 可能腾讯云翻新了接口文档,现在阅读起来,清晰了很多&…...