GC-分代收集器

news/2024/9/17 22:33:15/ 标签: jvm, java, 开发语言

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以及后续的不分代收集器,之所以可以做到低延迟的根本原因便在于此处。

  1. 白色 (White):
    ○ 未被访问的对象被标记为白色。
    ○ 白色对象是未被标记的对象,可能是垃圾。
  2. 灰色 (Gray):
    ○ 正在访问的对象被标记为灰色。
    ○ 灰色对象是已经被发现但还未完全处理的对象,即它们的引用还没有被完全遍历。
  3. 黑色 (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收集器对比如下:

在这里插入图片描述

对技术有兴趣的同学可以加群
在这里插入图片描述


http://www.ppmy.cn/news/1525679.html

相关文章

Java多线程编程-基础篇

多线程相关的概念 并发 并发是指在同一时间段内,两个或多个任务在同一个处理器上交替执行,使得在宏观上看起来像是同时进行。并发是通过快速切换任务来模拟同时执行的效果,实际上在任何一个时刻点上只有一个任务在执行。 也就是说&#xff0…

Linux 基础命令-文件权限与所有权

1. 文件权限概述 在Linux中,每个文件和目录都有与之关联的权限和所有权,来控制谁可以访问、修改或执行文件。文件权限与所有权可以防止未经授权的用户对文件进行访问或修改。 1.1 文件权限的组成 每个文件在Linux系统中都有三种类型的权限&#xff1a…

使用Ansible进行多云环境的自动化部署与管理

使用Ansible进行多云环境的自动化部署与管理 引言 随着云计算技术的飞速发展,多云环境已经成为现代企业IT架构的主流选择。多云环境不仅提供了更高的灵活性和可用性,还能有效降低供应商锁定的风险。然而,多云环境的管理和部署复杂性也随之增…

vue devtools的使用

vue devtools的使用 Vue Devtools 是一个强大的浏览器扩展,旨在帮助你调试和开发 Vue.js 应用。它支持 Chrome 和 Firefox 浏览器,并提供了一些工具和功能,可以让你更轻松地查看和调试 Vue 应用的状态和行为。以下是如何安装和使用 Vue Devtools 的详细指南。 安装 Vue De…

《Python青少年趣味编程108例》书籍介绍

文章目录 前言为什么选择Python?书籍介绍文章目录配套资源 前言 在这个数字化飞速发展的时代,编程已经成为了一项不可或缺的技能。对于青少年而言,学习编程不仅能够培养逻辑思维、解决问题的能力,还能激发无限创意,让…

【PyQt6 应用程序】一键视频解说克隆字幕切割版

在当今数字时代,视频解说已经成为影视剧宣传和观众互动的重要手段。然而,手动制作高质量的影视剧解说视频需要大量的时间和精力。为了简化这一过程并提高生产效率,我们开发了基于PyQt6的应用程序“一键视频解说克隆字幕切割版”。该应用程序能够自动复刻别人的影视剧解说视频…

概率论原理精解【13】

文章目录 在度量空间中,连续映射概述一、度量空间与距离函数二、连续映射的定义三、连续映射的等价定义四、连续映射的性质五、应用与例子 球形邻域刻画一、球形邻域的定义二、连续映射的球形邻域刻画三、等价性证明四、应用与例子 将度量空间上的连续映射推广到拓扑…

软件测试面试从哪方面面试?

一、面试基础题 简述测试流程: 什么是软件测试?软件测试的目的与原则 问:软件生存周期及其模型是什么? 什么是软件质量? 自动化测试脚本开发的主要步骤: 目前主要的测试用例设计方法是什么? 常见的测试用例设计…

二次规划及其MATLAB实现

引言 二次规划(Quadratic Programming, QP)是一类重要的优化问题,其目标函数为二次函数,约束条件为线性不等式或等式。二次规划问题在工程、经济、金融等领域有广泛应用,如投资组合优化、人脸表情动画的权重求解、机械…

后端开发刷题 | 把数字翻译成字符串(动态规划)

描述 有一种将字母编码成数字的方式&#xff1a;a->1, b->2, ... , z->26。 现在给一串数字&#xff0c;返回有多少种可能的译码结果 数据范围&#xff1a;字符串长度满足 0<n≤90 进阶&#xff1a;空间复杂度 O(n)&#xff0c;时间复杂度 O(n) 示例1 输入&a…

HJ36字符串加密

提示&#xff1a;文章 文章目录 前言一、背景二、 2.1 2.2 总结 前言 前期疑问&#xff1a; 本文目标&#xff1a; 一、背景 最近 二、 2.1 HJ36字符串加密 解题 #include <stdio.h> #include <stdbool.h>int GetStrIndex(char c, char* dict, int len) {…

Python中给定一个数组a = [2,3,9,1,0],找出其中最大的一个数,并打印出来 求解?

Python有内置的max函数可以取最大值&#xff1a; max([2,3,9,1,0])也可以使用sorted先排序&#xff0c;再索引取出最大值&#xff1a; sorted([2,3,9,1,0])[-1]如果不用内置函数&#xff0c;自己排序算法来找出最大值&#xff0c;也有很多选择。 比如冒泡排序、循环排序、交…

算法设计(二)

1.归并排序 介绍 归并排序是建立在归并操作上的一种有效&#xff0c;稳定的排序算法&#xff0c;该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并&#xff0c;得到完全有序的序列&#xff1b;即先使每个子序列有序&#xff0c;再使子序列段间有序。若将两个有…

【人工智能学习笔记】4_4 深度学习基础之生成对抗网络

生成对抗网络&#xff08;Generative Adversarial Network, GAN&#xff09; 一种深度学习模型&#xff0c;通过判别模型&#xff08;Discriminative Model&#xff09;和生成模型&#xff08;Generative Model&#xff09;的相互博弈学习&#xff0c;生成接近真实数据的数据分…

leecode100题-双指针-三数之和

给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0 。请你返回所有和为 0 且不重复的三元组。 答案中不可以包含重复的三元组。 示例 1&#xff1a; 输入…

【Hot100】LeetCode—169. 多数元素

目录 1- 思路题目识别技巧 2- 实现⭐136. 只出现一次的数字——题解思路 3- ACM 实现 原题链接&#xff1a;169. 多数元素 1- 思路 题目识别 识别1 &#xff1a;统计数组中出现数量多余 [n/2] 的元素 技巧 值相同&#xff0c;则对 count 1&#xff0c;如果不相同则对值进行…

线性代数 第六讲 特征值和特征向量_相似对角化_实对称矩阵_重点题型总结详细解析

文章目录 1.特征值和特征向量1.1 特征值和特征向量的定义1.2 特征值和特征向量的求法1.3 特征值特征向量的主要结论 2.相似2.1 相似的定义2.2 相似的性质2.3 相似的结论 3.相似对角化4.实对称矩阵4.1 实对称矩阵的基本性质4.2 施密特正交化 5.重难点题型总结5.1 判断矩阵能否相…

D - 1D Country(AtCoder Beginner Contest 371)

题目链接: D - 1D Country (atcoder.jp) 题目描述: 数据范围: 输入输出: 题目分析: 典型的l, r 区间问题&#xff0c;即是前缀和问题&#xff0c;但是注意到数据范围, 数据范围1e-9 到 1e9 数据范围&#xff0c;要是从最小到最大直接for循环去模拟的话&#xff0c;时间复杂度…

使用iperf3测试局域网服务器之间带宽

文章目录 一、下载安装1、windows2、centos 二、使用0、参数详解1、centos 一、下载安装 1、windows https://iperf.fr/iperf-download.php 拉到最下面选最新版&#xff1a; 2、centos yum install iperf3二、使用 0、参数详解 服务器或客户端&#xff1a; -p, --port #…

Python+Pytest框架,“api_key.py文件怎么编写“?

1、在"api_keyword"文件夹下新增"api_key.py" import allure import requests import json import jsonpath from deepdiff import DeepDifffrom config import *allure.title("测试用例执行") class ApiKey:allure.step(">>>:开…