【JVM】7种经典的垃圾收集器
文章目录
- 1. 垃圾收集器概述
- 2. Serial 收集器
- 3. ParNew 收集器
- 4. Paraller Scavenge 收集器
- 5. Serial Old收集器
- 6. Parller Old收集器
- 7. CMS 收集器
- 8. Garbage First 收集器
本文参考:深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)
1. 垃圾收集器概述
图中所示七种垃圾收集器虽然算不上先进技术,但是它们在实践中足够成熟,基本上可以认为是现在未来两、三年内,能够在生产环境上放心使用的所有垃圾收集器了。
这七种垃圾收集器是作用于不同分代的,两个收集器之间若有连线,则说明它们可以搭配使用。垃圾收集器的位置则表示了属于新生代还是老年代收集器。
垃圾收集器根据发展实践可以分为:
- 串行
- 吞吐量优先
- 响应时间优先
2. Serial 收集器
Serial收集器是最基础、历史最悠久的收集器。它是用于新生代的垃圾收集器。
这个收集器是一个单线程工作的收集器,“单线程”不仅仅代表了这个收集器只会使用一个处理器或一个收集线程去进行垃圾收集工作,更重要的是,Serial 收集器在进行垃圾收集的时候必须暂停其他所有工作,直到收集工作完成。
也就是说在用户不可知、不可控的情况下,把用户的正常工作的线程全部停掉,这是一个不能接受的事情。
即使 Serial 收集器是最早出现的垃圾收集器,但是如今HotSpot虚拟机运行在客户端模式下的默认新生代收集器依然是 Serial 收集器。
Serial 收集器的优点很简单,那就是简单高效,在内存资源受限的环境中,它是所有收集器里额外内存消耗最小的,对于单核处理器或核心数较小的处理器来说,Serial 收集器没有线程交互的开销,专心做垃圾收集因此保证了收集效率。
3. ParNew 收集器
ParNew 收集器实际上就是 Serail 收集器的多线程版本,除了同时使用多线程进行垃圾回收之外,其他的任何行为包括所有控制参数、收集算法等都与 Serail 收集器一样,并无太多创新之处
并且除了Serial收集器外,目前只有ParNew收集器可以与CMS收集器配合工作。
CMS是一款在强交互应用中几乎可称为具有时代意义的垃圾收集器,它是真正意义上支持并发的垃圾收集器,首次实现了让垃圾收集器线程在用户线程同时工作,所以,CMS的出现巩固了ParNew的地位。
ParNew 收集器在单核心处理器的环境绝对不必Serial收集器更好的效果,甚至存在线程交互的开销。
ParNew收集器通过超线程技术实现的伪双核处理器环境中都不能百分之百超越Serial。
不过随着处理器核心数量的增加,ParNew对于垃圾收集时的系统资源高效利用还是很有好处的,它默认开启的收集线程数和处理器核心线程数相同。
4. Paraller Scavenge 收集器
Paraller Scavenge 收集器是基于标记-复制算法实现的收集器,也是能够并行收集的多线程收集器。
该垃圾收集器常被称为“吞吐量优先收集器”
并行:并行描述的是多条垃圾收集器线程之间的关系,说明同一时间有多条这样的线程在协同工作,通常默认此时用户线程是处于等待状态
并发:并发描述的是垃圾收集器线程与用户线程之间的关系,说明同一时间垃圾收集器线程与用户线程都在运行。由于用户线程并未被冻结,所以程序仍然能响应服务请求,但由于垃圾收集器线程占用了一部分系统资源,此时应用程序的处理的吞吐量将受到一定影响。
Paraller Scavenge 收集器的特点是达到一个可控的吞吐量。
Parallel Scavenge 收集器提供了两个参数用于精确控制吞吐量,分别是控制最大垃圾收集停顿时间的-XX:MaxGCPauseMillis
参数以及直接设置吞吐量大小的-XX:GCTimeRatio
参数
-XX:MaxGCPauseMillis
:参数允许值是一个大于0的毫秒数,收集器会尽力保证内存回收花费时间不超过用户的设定值,**但是这个参数值不建议设置得更小一点,因为垃圾收集停顿时间是牺牲吞吐量和新生代空间为代价的。**系统把新生代调的小一点,垃圾收集速度肯定快一点,但是随之而来的就是频繁的垃圾收集,因此吞吐量也会下来。-XX:GCTimeRatio
:值应该是一个大于0小于100的正数,也就是垃圾收集时间总时间的比率,相当于吞吐量的倒数。比如设置为19,那么就是允许的最大垃圾收集器占用的时间为5%(即1/(1+19));默认为99,允许的最大1%(1/(1+99))为垃圾收集时间
5. Serial Old收集器
Serial Old收集器是Serial收集器的老年代版本,同样也是一个单线程收集器,使用标记-整理算法
如果在服务端模式下,它也可能有两种用途:一种是在JDK 5以及之前的版本中与 Parallel Scavenge 收集器搭配使用9,另外一种就是作为 CMS 收集器发生失败时的后备预案,在并发收集发生Concurrent Mode Failure 时使用。
6. Parller Old收集器
Parller Old收集器是Parller Scavenge收集器的老年代版本,支持多线程并发收集,基于标记-整理算法实现。
在Parller Old收集器没有出现之前,Parller Scavenge收集器只能和Serial Old收集器搭配使用,由于Serial Old收集器应用性能上的拖累,并不能是的Parller Scavenge收集器未必能发挥出最好的吞吐量最大化的效果。这组合甚至不如ParNew加CMS的组合来得优秀。
直到 Paraller old 收集器出现后,“吞吐量优先”收集器终于有了比较名副其实的搭配组合,在注重吞吐量或者处理器资源较为稀缺的场合,都可以优先考虑 Paraller Scavenge 加Paraller Old 收集器这个组合。
7. CMS 收集器
CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。目前很大一部分的 Java 应用集中在互联网网站或者基于浏览器的 B/S 系统的服务端上,这类应用通常都会较为关注服务的响应速度,希望系统停顿时间尽可能短,以给用户带来良好的交互体验。
CMS收集器是基于标记-清除算法实现的。它的回收垃圾的步骤如下
-
初始标记
- 需要Stop The Word,仅仅标记从GC Roots的直接关联对象,速度很快
-
并发标记
- 从GC Roots的直接关联对象开始遍历整个对象图的过程,过程耗时但不需要停顿用户线程,可以与垃圾收集线程一起并发允许
-
重新标记
- 需要Stop The Word,为的是修正并发标记期间,因用户程序继续允许而导致标记产生变动的拿一些对象的标记记录。
- 停顿时间比初始标记时间常,但比并发标记时间短
-
并发清除
- 清除标记阶段判断已经死亡的对象,由于不需要移动存活对象,所以这个阶段也是可以和用户进程同时运行的
CMS的优点的优点有并发收集、低停顿。
不过CMS并没有达到完美,它有以下几个缺点
- CMS收集器对处理器资源非常敏感
- CMS无法处理浮动垃圾
- 由于并发标记和并发清除阶段,用户线程是继续运行的,程序在运行的时候自然会产生新的垃圾对象。
- 由于使用标记-清除算法实现,所以会导致空间碎片比较多。
8. Garbage First 收集器
Garbage First 收集器也成为G1收集器,它是垃圾收集器技术发展历史上的里程碑式的成果,它开创了收集器面向局部收集的设计思路和基于 Region 的内存布局形式。
G1收集器面向堆内存任何部分来组成回收集 (Collection Set,一般简称 CSet)进行回收,衡量标准不再是它属于哪个分代,而是哪块内存中存放的垃圾数量最多,回收收益最大,这就是 G1 收集器的 Mixed GC 模式。
G1开创的基于 Region 的堆内存布局是它能够实现这个目标的关键。虽然 G1 也仍是遵循分代收集理论设计的,但其堆内存的布局与其他收集器有非常明显的差异:G1 不再坚持固定大小以及固定数量的分代区域划分,而是把连续的 Java 堆划分为多个大小相等的独立区域(Region),每一个Region 都可以根据需要,扮演新生代的 Eden 空间、Survivor 空间或者老年代空间。收集器能够对扮演不同角色的 Region 采用不同的策略去处理,这样无论是新创建的对象还是已经存活了一段时间、熬过多次收集的旧对象都能获取很好的收集效果。
Region 是 G1收集器的单位回收的最小单位,这样做可以有计划避免整个JAVA堆中进行全区域的垃圾收集。并且G1收集器会跟踪各个Region的价值大小,也就是回收所获得的空间大小以及回收所需要的时间的经验值,在后台形成一个优先队列,再根据用户设定的允许的停顿时间,优先处理那些回收价值大的Region,这样保证了G1收集器在有限的时间内获取尽可能高的收集效率。
G1收集器的运作步骤
- 初始标记
- 仅仅只是标记一下GC Roots 能直接关联到的对象并且修改 TAMS 指针的值,让下一阶段用户线程并发运行时,能正确地在可用的 Region 中分配新对象。这个阶段需要停顿线程,但耗时很短,而且是借用进行Minor GC 的时候同步完成的,所以G1 收集器在这个阶段实际并没有额外的停顿。
- 并发标记
- 从GC Root开始对堆中对象进行可达性分析,递归扫描整个堆里的对象图,找出要回收的对象,这阶段耗时较长,但可与用户程序并发执行。当对象图扫描完成以后,还要重新处理 SATB 记录下的在并发时有引用变动的对象。
- 最终标记
- 对用户线程做另一个短暂的暂停,用于处理并发阶段结束后仍遗留下来的最后那少量的 SATB 记录。
- 筛选回收
- 负责更新 Region 的统计数据,对各个Region 的回收价值和成本进行排序,根据用户所期望的停顿时间来制定回收计划,可以自由选择任意多个 Region 构成回收集,然后把决定回收的那一部分Region 的存活对象复制到空的 Region 中,再清理掉整个旧 Region 的全部空间。这里的操作涉及存活对象的移动,是必须暂停用户线程,由多条收集器线程并行完成的。
相关文章:

【JVM】7种经典的垃圾收集器
文章目录1. 垃圾收集器概述2. Serial 收集器3. ParNew 收集器4. Paraller Scavenge 收集器5. Serial Old收集器6. Parller Old收集器7. CMS 收集器8. Garbage First 收集器本文参考:深入理解Java虚拟机:JVM高级特性与最佳实践(第3版ÿ…...
2023/2/12总结
滑动窗口(1)滑动窗口是一种基于双指针的思想,两个指针指向的元素形成一个窗口。一般用于求取数组或字符串的某个子串、子序列、最长最短等最值或者求某个目标值时,并且该问题本身可以通过暴力解决。滑动窗口分为固定窗口和不定窗口…...
Linux之正则表达式
正则表达式是组成“操作”的基本语法,而这些“操作”是应用于Sed和Awk必备的能力。因此只有了解了正则表达式,才能学好Sed和Awk。正则表达式分为基础正则表达式(Regular Expression)与扩展正则表达式(Extended Regular…...
前端高频面试题-HTML和CSS篇(一)
💻 前端高频面试题-HTML和CSS篇(一) 🏠专栏:前端面试题 👀个人主页:繁星学编程🍁 🧑个人简介:一个不断提高自我的平凡人🚀 🔊分享方向…...
Redis 专题总结
1. 什么是Redis ? 处理:内容缓存,主要用于处理大量数据的高访问负载。Redis是一款高性能的NOSQL系列的非关系型数据库,NoSQL(NoSQL Not Only SQL),意即“不仅仅是SQL”,是一项全新的数据库理念࿰…...
【Python百日进阶-Web开发-Vue3】Day515 - Vue+ts后台项目2:登录页面
文章目录 一、创建登录路由1.1 安装 Vue VSCode Snippets插件1.2 处理路径引用的红色波浪线1.3 入口文件 main.ts1.4 主组件 App.vue1.5 路由文件 router/index.ts1.6 首页组件 views/HomeView.vue1.7 登录组件 views/LoginView.vue二、实现登录页面的表单展示2.1 element-plus…...

【博客620】prometheus如何优化远程读写的性能
prometheus如何优化远程读写的性能 场景 为了解决prometheus本地存储带来的单点问题,我们一般在高可用监控架构中会使用远程存储,并通过配置prometheus的remote_write和remote_read来对接 远程写优化:remote_write 远程写的原理:…...

redis可视工具AnotherRedisDesktopManager的使用
redis可视工具AnotherRedisDesktopManager的使用 简介 Another Redis DeskTop Manager 是一个开源项目,提供了以可视化的方式管理 Redis 的功能,可供免费下载安装,也可以在此基础上进行二次开发,主要特点有: 支持 W…...

【idea】idea生产类注释和方法注释
网上有很多类似的文章,但是我在按照他们的文章设置后,出现了一些问题,因此我这边在解决了问题后,总结一篇文章,发出来给大家借鉴一下。在此先说明一下idea的版本,是2020.1.3 设置动态模板,File…...

jenkins +docker+python接口自动化之jenkins容器安装python3(二)
jenkins dockerpython接口自动化之jenkins容器安装python3(二) 目录:导读 前提是在docker下已经配置好jenkins容器了,是将python安装在jenkins容器下的 1、先看你的jenkins是否安装好 2、以root权限进入jenkins容器࿱…...

go 命令行工具整理
这里会整理可能会使用到的命令行参数,比如 go build、go run,诸如此类。了解这些内容对我们工作会有什么帮助吗?更多的时候,是能让我们理解代码编译的意图,或者,给我们一种排查问题的手段。 比方说&#x…...

RuntimeError: CUDA out of memory
今天在训练模型的时候突然报了显存不够的问题,然后分析了一下,找到了解决的办法,这里记录一下,方便以后查阅。 注:以下的解决方案是在模型测试而不是模型训练时出现这个报错的! RuntimeError: CUDA out of…...
Kubernetes1.25中Redis集群部署实例
1、概述我们知道在 Kubernetes 容器编排平台中, 我们可以非常方便的进行应用的扩容缩, 同时也能非常方便的进行业务的迭代,本章主要讲解在Kubernetes1.25搭建Redis单实例和Redis集群主从同步的环境流程步骤, 如果是高频访问重要的线上业务我们最好是部署在物理机器上…...

C++11实现计算机网络中的TCP/IP连接(Windows端)
目录引言1、TCP2、IP2.1 IP路由器3、TCP/IP4、TCP/IP协议C11实现参考文献引言 TCP/IP 指传输控制协议/网际协议(Transmission Control Protocol / Internet Protocol)。[1] 在TCP/IP协议簇中主要包含以下内容: TCP (传输控制协议) - 应用程序…...

Spring框架自定义实现IOC基础功能/IDEA如何手动实现IOC功能
继续整理记录这段时间来的收获,详细代码可在我的Gitee仓库Java设计模式克隆下载学习使用! 7.4 自定义Spring IOC 创建新模块,结构如图![[Pasted image 20230210173222.png]] 7.4.1 定义bean相关POJO类 7.4.1.1 定义propertyValue类 /** …...

pip离线安装windows版torch
文章目录前言conda创建虚拟环境安装torchtorch官网在线安装离线手动安装测试是否安装成功后记前言 学习的时候遇到几个机器学习相关的项目,由于不同的项目之间用到的依赖库不太一样,于是想利用conda为不同的项目创建不同的环境方便管理和运行࿰…...

Redis核心知识点
Redis核心知识点Redis核心知识点大全五种数据类型redis整合SpringBoot序列化问题渐进式扫描慢查询缓存相关问题数据库和缓存谁先更新缓存穿透缓存雪崩缓存击穿实际应用超卖问题分布式锁全局唯一ID充当消息队列Feed流附近商户签到HyperLogLog实现UV统计持久化RDBAOF持久化小结事…...

14. 最长公共前缀
14. 最长公共前缀 一、题目描述: 编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀,返回空字符串 “”。 示例 1: 输入:strs [“flower”,“flow”,“flight”] 输出:“fl” 示例 2: …...

SignalR注册成Windows后台服务,并实现web前端断线重连
注意下文里面的 SignalR 不是 Core 版本,而是 Framework 下的 本文使用的方式是把 SignalR 写在控制台项目里,再用 Topshelf 注册成 Windows 服务 这样做有两点好处 传统 Window 服务项目调试时需要“附加到进程”,开发体验比较差…...

【前端笔试题二】从一个指定数组中,每次随机取一个数,且不能与上次取数相同,即避免相邻取数重复
前言 本篇文章记录下我在笔试过程中遇到的真实题目,供大家参考。 1、题目 系统给定一个数组,需要我们编写一个函数,该函数每次调用,随机从该数组中获取一个数,且不能与上一次的取数相同。 2、思路解析 数组已经有了…...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄
文|魏琳华 编|王一粟 一场大会,聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中,汇集了学界、创业公司和大厂等三方的热门选手,关于多模态的集中讨论达到了前所未有的热度。其中,…...

深入理解JavaScript设计模式之单例模式
目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式(Singleton Pattern&#…...

376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...
Matlab | matlab常用命令总结
常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...
【HTML-16】深入理解HTML中的块元素与行内元素
HTML元素根据其显示特性可以分为两大类:块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...
多模态图像修复系统:基于深度学习的图片修复实现
多模态图像修复系统:基于深度学习的图片修复实现 1. 系统概述 本系统使用多模态大模型(Stable Diffusion Inpainting)实现图像修复功能,结合文本描述和图片输入,对指定区域进行内容修复。系统包含完整的数据处理、模型训练、推理部署流程。 import torch import numpy …...

解读《网络安全法》最新修订,把握网络安全新趋势
《网络安全法》自2017年施行以来,在维护网络空间安全方面发挥了重要作用。但随着网络环境的日益复杂,网络攻击、数据泄露等事件频发,现行法律已难以完全适应新的风险挑战。 2025年3月28日,国家网信办会同相关部门起草了《网络安全…...

【从零开始学习JVM | 第四篇】类加载器和双亲委派机制(高频面试题)
前言: 双亲委派机制对于面试这块来说非常重要,在实际开发中也是经常遇见需要打破双亲委派的需求,今天我们一起来探索一下什么是双亲委派机制,在此之前我们先介绍一下类的加载器。 目录 编辑 前言: 类加载器 1. …...

Rust 开发环境搭建
环境搭建 1、开发工具RustRover 或者vs code 2、Cygwin64 安装 https://cygwin.com/install.html 在工具终端执行: rustup toolchain install stable-x86_64-pc-windows-gnu rustup default stable-x86_64-pc-windows-gnu 2、Hello World fn main() { println…...

【Linux】自动化构建-Make/Makefile
前言 上文我们讲到了Linux中的编译器gcc/g 【Linux】编译器gcc/g及其库的详细介绍-CSDN博客 本来我们将一个对于编译来说很重要的工具:make/makfile 1.背景 在一个工程中源文件不计其数,其按类型、功能、模块分别放在若干个目录中,mak…...