JVM 垃圾回收器 详解

news2025/6/8 10:01:51

垃圾收集器

  • Serial+Serial Old:单线程回收,适用于单核CPU场景
  • ParNew+CMS:暂停时间较短,适用于大型互联网应用中与用户交互的部分
  • Paraller Scavenge+Parallel Old:吞吐量高,适用于后台进行大量数据操作
  • G1:适用于较大堆,具有可控暂停时间

七种经典垃圾回收器

Serial 收集器:

在这里插入图片描述
最基础、历史最悠久的收集器,是一个单线程工作的收集器,工作于新生代,使用标记-复制算法:
在这里插入图片描述

简单而高效(与其他收集器的单线程相比),对于内存资源受限的环境,它是所有收集器里额外内存消耗最小的;对于单核处理器或处理器核心数较少的环境来说,Serial收集器由于没有线程交互的开销,专心做垃圾收集自然可以获得最高的单线程收集效率。Serial收集器对于运行在客户端模式下的虚拟机来说是一个很好的选择

ParNew 收集器:

在这里插入图片描述

ParNew收集器实质上是Serial收集器的多线程并行版本,ParNew收集器除了支持多线程并行收集之外,其他与Serial收集器相比并没有太多创新之处,工作于新生代,使用标记-复制算法

在这里插入图片描述

Parallel Scavenge 收集器:

在这里插入图片描述

Parallel Scavenge 工作于新生代,使用标记-复制算法,也是能够并行收集的多线程收集器。Parallel Scavenge收集器的目标则是达到一个可控制的吞吐量。所谓吞吐量就是处理器用于运行用户代码的时间与处理器总消耗时间的比值,即:

在这里插入图片描述

Parallel Scavenge 收集器提供了两个参数用于精确控制吞吐量,分别是控制最大垃圾收集停顿时间的-XX:MaxGCPauseMillis参数以及直接设置吞吐量大小的-XX:GCTimeRatio 参数。

  • -XX:MaxGCPauseMillis 参数允许的值是一个大于0的毫秒数,收集器将尽力保证内存回收花费的时间不超过用户设定值。
  • -XX:GCTimeRatio参数的值则应当是一个大于0小于100的整数,也就是垃圾收集时间占总时间的比率,相当于吞吐量的倒数。譬如把此参数设置为19,那允许的最大垃圾收集时间就占总时间的5%(即1/(1+19)),默认值为99,即允许最大1%(即1/(1+99))的垃圾收集时间。

Serial Old 收集器:

在这里插入图片描述

Serial Old 是 Serial 收集器的老年代版本,使用标记-整理算法,它同样是一个单线程收集器。这个收集器的主要意义也是供客户端模式下的HotSpot虚拟机使用。如果在服务端模式下,它也可能有两种用途:一种是在JDK 5以及之前的版本中与Parallel Scavenge收集器搭配使用(效果不是很好),另外一种就是作为CMS收集器发生失败时的后备预案,在并发收集发生Concurrent Mode Failure时使用。

在这里插入图片描述

Parallel Old 收集器:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Parallel Old 是 Parallel Scavenge 收集器的老年代版本,基于标记-整理算法实现,支持多线程并发收集。主要解决了Parallel Scavenge的老年代垃圾收集器的搭配问题。这个收集器是直到JDK 6时才开始提供的,在此之前,新生代的 Parallel Scavenge 收集器一直处于相当尴尬的状态,原因是如果新生代选择了Parallel Scavenge收集器,老年代除了Serial Old(PS MarkSweep)收集器以外别无选择,而老年代的Serial Old收集器在服务端表现并不良好,这种组合的总吞吐量不一定比ParNew加CMS来得优秀,而Parallel Scavenge主打的就是吞吐量可控制

直到Parallel Old 收集器出现后,“吞吐量优先”收集器终于有了比较名副其实的搭配组合,在注重吞吐量或者处理器资源较为稀缺的场合,都可以优先考虑Parallel Scavenge 加 Parallel Old 收集器这个组合。

在这里插入图片描述

CMS (Concurrent Mark Sweep)收集器:

在这里插入图片描述

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

JDK1.5时引入,JDK9被标记弃用,JDK14被移除

主打获取最短回收停顿时间(Stop The World),工作于老年代,基于标记-清除算法(混合标记-整理),整个过程分为四个步骤:

  1. 初始标记(CMS initial mark)
  2. 并发标记(CMS concurrent mark)
  3. 重新标记(CMS remark)
  4. 并发清除(CMS concurrent sweep)

其中初始标记、重新标记这两个步骤仍然需要“Stop The World”。初始标记需要标记GC Roots(包括年轻代存活下来的对象,因为需要解决跨代引用问题)能直接关联到的对象;并发标记阶段就是从GC Roots的直接关联对象开始遍历整个对象图的过程,这个过程耗时较长但是不需要停顿用户线程,可以与垃圾收集线程一起并发运行;而重新标记阶段则是为了修正并发标记期间, 因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录(三色标记中的增量更新解决方案),这个阶段的停顿时间通常会比初始标记阶段稍长一些,但也远比并发标记阶段的时间短;最后是并发清除阶段,清理删除掉标记阶段判断的已经死亡的对象,由于不需要移动存活对象,所以这个阶段也是可以与用户线程同时并发的。

在这里插入图片描述

CMS(Concurrent Mark-Sweep)垃圾收集器的缺点

  1. 对处理器资源敏感:
    • CMS 在并发阶段会占用一部分处理器资源,导致应用程序变慢,降低总吞吐量。
    • 默认启动的回收线程数是(处理器核心数量 + 3)/ 4,当处理器核心数量较少时,CMS 对用户程序的影响可能较大。
  2. 浮动垃圾问题:
    • 在 CMS 的并发标记和并发清理阶段,用户线程继续运行,会产生新的垃圾对象(浮动垃圾)。
    • 这些浮动垃圾无法在当次垃圾收集中处理,只能留待下一次收集。
    • 浮动垃圾可能导致 “Concurrent Mode Failure”,进而触发完全 “Stop The World” 的 Full GC。
  3. 内存预留与并发失败风险:
    • CMS 需要预留一部分老年代空间供用户线程使用,不能等到老年代几乎被填满时再收集。
    • 如果预留空间不足,可能出现 “Concurrent Mode Failure”,导致虚拟机启用 Serial Old 收集器进行 Full GC,停顿时间较长。
  4. 内存碎片问题:
    • CMS 使用标记-清除算法,导致内存中存在空间碎片。
    • 为了解决碎片问题,CMS 提供了 -XX:+UseCMSCompactAtFullCollection 参数(JDK 9 开始废弃),在 Full GC 时进行内存碎片整理,但整理过程无法并发,导致停顿时间变长。
    • 另一个参数 -XX:CMSFullGCsBeforeCompaction(JDK 9 开始废弃)用于控制在进行若干次不整理空间的 Full GC 后,下一次 Full GC 前进行碎片整理。

Garbage First (G1)收集器:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

优点

  • 支持巨大的堆空间回收,并有较高的吞吐量。对比较大的堆延迟可控,如超过6G的堆回收时
  • 不会产生内存碎片
  • 并发标记的SATB算法效率高,比CMS的算法效率高
  • 支持多CPU并行垃圾回收
  • 允许用户设置最大暂停时间

JDK7引入,JDK9取代CMS成为默认垃圾收集器,至少要4G内存才推荐使用G1

G1是一款主要面向服务端应用的垃圾收集器。在G1收集器出现之前的所有其他收集器,包括CMS在内,垃圾收集的目标范围要么是整个新生代 (Minor GC),要么就是整个老年代(Major GC),再要么就是整个Java堆(Full GC)。 而G1跳出了这个樊笼,它可以面向堆内存任何部分来组成回收集(Collection Set,一般简称CSet)进行回收,衡量标准不再是它属于哪个分代,而是哪块内存中存放的垃圾数量最多,回收收益最大,这就是G1收集器的Mixed GC模式。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
G1 不再坚持固定大小以及固定数量的分代区域划分,而是把连续的Java堆划分为多个大小相等的独立区域(Region),每一个Region都可以根据需要,扮演新生代的Eden空间、 Survivor 空间,或者老年代空间。收集器能够对扮演不同角色的Region采用不同的策略去处理

Region 中还有一类特殊的Humongous区域,专门用来存储大对象。G1认为只要大小超过了一个Region容量一半的对象即可判定为大对象。而对于那些超过了整个Region容量的超级大对象,将会被存放在N个连续的Humongous Region之中,G1的大多数行为都把Humongous Region作为老年代的一部分来进行看待。

G1收集器之所以能建立可预测的停顿时间模型,是因为它将Region作为单次回收的最小单元,即每次收集到的内存空间都是Region大小的整数倍,这样可以有计划地避免在整个Java堆中进行全区域的垃圾收集。更具体的处理思路是让G1收集器去跟踪各个Region里面的垃圾堆积的“价值”大小,价值即回收所获得的空间大小以及回收所需时间的经验值,然后在后台维护一个优先级列表,每次根据用户设定允许的收集停顿时间(使用参数-XX:MaxGCPauseMillis 指定,默认值是200毫秒),优先处理回收价值收益最大的那些Region。

G1 收集器有以下细节:

  • 每个Region都有自己的记忆集,这些记忆集会记录下别的Region指向自己的指针,并标记这些指针分别在哪些卡页的范围之内,用于解决跨代引用问题

  • 通过原始快照 解决 并发标记阶段 线程与用户线程同时进行 带来的 对象引用关系改变问题

  • 程序要继续运行就肯定会持续有新对象被创建,G1为每一个Region设计了两个名为TAMS(Top at Mark Start)的指针,把 Region中的一部分空间划分出来用于并发回收过程中的新对象分配,并发回收时新分配的对象地址都必须要在这两个指针位置以上。G1收集器默认在这个地址以上的对象是被隐式标记过的,即默认它们是存活的,不纳入回收范围。

  • 三种GC模式,Young GC、Mixed GC和Full GC

Young GC

1、新创建的对象会存放在Eden区。当G1判断年轻代区不足(max默认60%),无法分配对象时需要回收时会执行Young GC。

2、标记出Eden和Survivor区域中的存活对象,

3、根据配置的最大暂停时间选择某些区域将存活对象复制到一个新的Survivor区中(年龄+1),清空这些区域。

4、后续Young GC时与之前相同,只不过Survivor区中存活对象会被搬运到另一个Survivor区。

5、当某个存活对象的年龄到达阈值(默认15),将被放入老年代。

6、部分对象如果大小超过Region的一半,会直接放入老年代,这类老年代被称为Humongous区。比如堆内存是4G,每个Region是2M,只要一个大对象超过了1M就被放入Humongous区,如果对象过大会横跨多个Region。

MixedGC

多次Young gc之后,会出现很多Old老年代区,此时总堆占有率达到阈值时(-XX:InitiatingHeapOccupancyPercent默认45%)会触发混合回收Mixed GC,回收所有年轻代和部分老年代的对象以及大对象区。采用复制算法来完成。

混合回收分为如下步骤:

初始标记(initial mark)
并发标记(concurrent mark)
最终标记(remark或者Finalize Marking):只管漏标,不管新创建、不再关联的对象。这里使用的算法远比CMS的快
并发清理(cleanup):G1对老年代的清理会选择存活度最低的区域来进行回收,这样可以保证回收效率最高,这也是G1(Garbage first)名称的由来。最后清理阶段使用复制算法,不会产生内存碎片。

在这里插入图片描述

Full GC

在这里插入图片描述

低延迟垃圾收集器:

Shenandoah和ZGC,几乎整个工作过程全部都是并发的,只有初始标记、最终标记这些阶段有短暂的停顿,这部分停顿的时间基本上是固定的,与堆的容量、堆中对象的数量没有正比例关系。实际上,它们都可以在任意可管理的(譬如现在 ZGC只能管理4TB以内的堆)堆容量下, 实现垃圾收集的停顿都不超过十毫秒这种以前听起来是天方夜谭、匪夷所思的目标。这两款目前仍处于实验状态的收集器,被官方命名为“低延迟垃圾收集器”

Shenandoah收集器:

RedHat开发的收集器,捐赠给OpenJDK,在OracleJDK中没有,主要是改进了G1收集器在回收阶段无法与用户进程并发的问题

ZGC 收集器:

JDK11推出

与Shenandoah和G1一样,ZGC也采用基于Region 的堆内存布局,但与它们不同的是,ZGC的Region具有动态性——动态创建和销毁,以及动态的区域容量大小。

  • 小型Region:容量固定为 2MB,用于放置小于256KB的小对象
  • 中型Region:容量固定为32MB,用于放置大于等于256KB但小于4MB的对象
  • 大型Region:容量不固定,可以动态变化,但必须为2MB的整数倍,用于放置4MB或以上的大对象。每个大型Region中只会存放一个大对象,大型Region在ZGC的实现中是不会被重分配(重分配是ZGC的一种处理动作,用于复制对象的收集器阶段)的,因为复制一个大对象的代价非常高昂。

ZGC收集器有一个标志性的设计是它采用的染色指针技术,染色指针是一种直接将少量额外的信息存储在指针上的技术

Linux下64位指针的高18位不能用来寻址,但剩余的46位指针所能支持的64TB内存在今天仍然能够充分满足大型服务器的需要。鉴于此,ZGC的染色指针技术继续盯上了这剩下的46位指针宽度,将其高4位提取出来存储四个标志信息。通过这些标志位,虚拟机可以直接从指针中看到其引用对象的三色标记状态、是否进入了重分配集(即被移动过)、是否只能通过finalize()方法才能被访问到。由于这些标志位进一步压缩了原本就只有46位的地址空间,也直接导致ZGC能够管理的内存不可以超过4TB(2的42次幂)

ZGC不通过原始快照或增量更新来实现并发标记,而是通过染色指针

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2404000.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

FreeRTOS任务之深入篇

目录 1.Tick1.1 Tick的概念1.2 Tick与任务调度1.3 Tick与延时函数 2.任务状态2.1 运行状态 (Running)2.2 就绪状态 (Ready)2.3 阻塞状态 (Blocked)5.4 暂停状态 (Suspended)2.5 特殊状态:删除状态 (Deleted)5.6 任务状态转换2.7 实验 3.Delay函数3.1 两个函数3.2 实…

Linux 系统、代码与服务器进阶知识深度解析

在数字化时代,Linux 系统凭借其开源、稳定、安全的特性,成为服务器领域和软件开发的核心支柱。除了算法优化技巧,Linux 系统在网络服务、容器化技术、服务器安全等方面也蕴含着丰富的知识和实用技术。接下来,我们将深入探讨这些领…

人工智能--AI换脸

本文实现了一个简易的人脸交换程序,主要功能包括:1)检查所需的模型文件是否存在;2)使用预训练的Caffe模型检测图像中的人脸;3)将源图像的人脸区域通过泊松融合无缝地替换到目标图像上。程序通过OpenCV的DNN模块加载人脸检测模型&a…

NLP学习路线图(二十七):Transformer编码器/解码器

一、Transformer概览:抛弃循环,拥抱注意力 传统RNN及其变体(如LSTM、GRU)处理序列数据时存在顺序依赖的瓶颈:必须逐个处理序列元素,难以并行计算,且对长程依赖建模能力较弱。Transformer的革命…

【机器学习】支持向量机实验报告——基于SVM进行分类预测

目录 一、实验题目描述 二、实验步骤 三、Python代码实现基于SVM进行分类预测 四、我的收获 五、我的感受 一、实验题目描述 实验题目:基于SVM进行分类预测 实验要求:通过给定数据,使用支持向量机算法(SVM)实现分…

HA: Wordy靶场

HA: Wordy 来自 <HA: Wordy ~ VulnHub> 1&#xff0c;将两台虚拟机网络连接都改为NAT模式 2&#xff0c;攻击机上做namp局域网扫描发现靶机 nmap -sn 192.168.23.0/24 那么攻击机IP为192.168.23.128&#xff0c;靶场IP192.168.23.130 3&#xff0c;对靶机进行端口服务探…

中国移动6周年!

基站超过250万个 网络规模全球最大、质量最优 覆盖全国96%人口 在全国率先实现乡乡双千兆 服务用户超5.7亿 网络上下行均值接入速率均居行业首位 行业应用快速推广&#xff0c;数量超5万个 3CC、RedCap、通感一体、 无线AI改造等技术成熟商用 客户品牌持续升级&#x…

408第一季 - 数据结构 - 树与二叉树II

二叉树的先中后序遍历 理解 那主播&#xff0c;请问你有没有更快的遍历方式呢 有的&#xff0c;兄弟有的 以中序遍历为例啊 找左边有没有东西&#xff0c;左边没东西那它就自由了&#xff0c;就按上面的图举例子 A左边有东西&#xff0c;是B&#xff0c;B左边没东西&#xf…

从上下文学习和微调看语言模型的泛化:一项对照研究

大型语言模型表现出令人兴奋的能力&#xff0c;但也可以从微调中表现出令人惊讶的狭窄泛化。例如&#xff0c;他们可能无法概括为简单的关系反转&#xff0c;或者无法根据训练信息进行简单的逻辑推理。这些未能从微调中概括出来的失败可能会阻碍这些模型的实际应用。另一方面&a…

智慧城市建设方案

第1章 总体说明 1.1 建设背景 1.2 建设目标 1.3 项目建设主要内容 1.4 设计原则 第2章 对项目的理解 2.1 现状分析 2.2 业务需求分析 2.3 功能需求分析 第3章 大数据平台建设方案 3.1 大数据平台总体设计 3.2 大数据平台功能设计 3.3 平台应用 第4章 政策标准保障…

pygame开发的坦克大战

使用Python和Pygame开发的精美坦克大战游戏。这个游戏包含玩家控制的坦克、敌方坦克、各种障碍物、爆炸效果和完整的游戏机制。 游戏说明 这个坦克大战游戏包含以下功能&#xff1a; 游戏特点 玩家控制&#xff1a;使用方向键移动坦克&#xff0c;空格键射击 敌人AI&#x…

功能安全实战系列09-英飞凌TC3xx LBIST开发详解

本文框架 0. 前言1.What?1.1 基本原理1.1.1 检测范围1.1.2 LBIST与锁步核对比1.1.3 控制寄存器1.2 关联Alarm2. How?2.1 LBIST触发?2.1.1 SSW配置自动触发2.1.2 软件手动触发LBIST2.2 实现策略2.3 测试篇LBIST对启动时间的影响如何确定当前LBIST是否已使能?如何确定当前LBI…

一个完整的日志收集方案:Elasticsearch + Logstash + Kibana+Filebeat (二)

&#x1f4c4; 本地 Windows 部署 Logstash 连接本地 Elasticsearch 指南 ✅ 目标 在本地 Windows 上安装并运行 Logstash配置 Logstash 将数据发送至本地 Elasticsearch测试数据采集与 ES 存储流程 &#x1f9f0; 前提条件 软件版本要求安装说明Java17Oracle JDK 下载 或 O…

RT-Thread内核组成——内核移植

内核移植就是指将 RT-Thread 内核在不同的芯片架构、不同的板卡上运行起来&#xff0c;能够具备线程管理和调度&#xff0c;内存管理&#xff0c;线程间同步和通信、定时器管理等功能。移植可分为 CPU 架构移植和 BSP&#xff08;Board support package&#xff0c;板级支持包&…

基于Java(SpringBoot、Mybatis、SpringMvc)+MySQL实现(Web)小二结账系统

结账系统 1.引言 1.1.编写目的 此说明书在概要设计的基础上&#xff0c;对小二结账系统的各个模块、程序分别进行了实现层面上的要求和说明。在以下的详细设计报告中将对在本阶段中对系统所做的所有详细设计进行说明。在本阶段中&#xff0c;确定应该如何具体的实现所要求的…

三维GIS开发cesium智慧地铁教程(4)城市白模加载与样式控制

一、添加3D瓦片 <!-- 核心依赖引入 --> <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"><!-- 模型数据路径 --> u…

越狱蒸馏-可再生安全基准测试

大家读完觉得有帮助记得关注&#xff01;&#xff01;&#xff01; 摘要 大型语言模型&#xff08;LLMs&#xff09;正迅速部署在关键应用中&#xff0c;这引发了对稳健安全基准测试的迫切需求。我们提出了越狱提炼&#xff08;JBDISTILL&#xff09;&#xff0c;这是一种新颖…

64、js 中require和import有何区别?

在 JavaScript 中&#xff0c;require 和 import 都是用于模块导入的语法&#xff0c;但它们属于不同的模块系统&#xff0c;具有显著的区别&#xff1a; 1. 模块系统不同 require 属于 CommonJS 模块系统&#xff08;Node.js 默认使用&#xff09;。 语法&#xff1a;const…

手机号段数据库与网络安全应用

手机号段数据库的构成与原理 手机号段数据库存储着海量手机号段及其关联信息&#xff0c;包括号段起始与结束号码、运营商归属、地区编码、卡类型等核心数据。这些数据主要来源于通信管理机构的官方分配信息、运营商的业务更新数据以及合法采集的使用数据。经过数据清洗、校验…

Kafka 入门指南与一键部署

Kafka 介绍 想象一下你正在运营一个大型电商平台&#xff0c;每秒都有成千上万的用户浏览商品、下单、支付&#xff0c;同时后台系统还在记录用户行为、更新库存、处理物流信息。这些海量、持续产生的数据就像奔腾不息的河流&#xff0c;你需要一个强大、可靠且实时的系统来接…