垃圾收集算法与收集器

在 JVM 中,垃圾收集(Garbage Collection, GC)算法的核心目标是自动回收无用对象的内存,同时尽量减少对应用性能的影响。以下是 JVM 中主要垃圾收集算法的原理、流程及实际应用场景的详细介绍:


一、标记-清除算法(Mark-Sweep)

原理
  • 标记阶段:从 GC Roots(如栈引用、静态变量)出发,遍历对象图,标记所有存活对象。
  • 清除阶段:扫描堆内存,回收未被标记的对象所占用的内存(直接释放,不整理内存)。
工作流程
  1. 暂停所有应用线程(STW,Stop-The-World),启动标记。
  2. 标记完成后,清除未标记的垃圾对象。
  3. 恢复应用线程。
优点
  • 实现简单,内存回收效率较高。
缺点
  • 内存碎片化:清除后会产生不连续的内存空间,可能无法分配大对象,最终触发 Full GC。
  • 两次 STW:标记和清除阶段均需暂停应用线程。
应用场景
  • CMS 收集器的老年代回收(仅清除阶段,标记阶段并发执行)。

二、标记-整理算法(Mark-Compact)

原理
  • 标记阶段:与标记-清除相同,标记所有存活对象。
  • 整理阶段:将所有存活对象向内存一端移动,清理边界外的内存(消除碎片)。
工作流程
  1. STW 标记存活对象。
  2. 将存活对象移动到内存一端,保持连续。
  3. 清除边界外的内存。
  4. 恢复应用线程。
优点
  • 无内存碎片:整理后内存连续,适合长期运行的应用。
  • 空间利用率高:减少大对象分配失败的概率。
缺点
  • 两次 STW 且时间长:移动对象需要额外时间,尤其是堆较大时。
  • 内存移动开销:对象复制可能影响吞吐量。
应用场景
  • Serial OldParallel Old 收集器的老年代回收。
  • G1 的混合回收阶段(复制存活对象到新 Region)。

三、复制算法(Copying)

原理
  • 将堆内存分为两块(From 和 To 空间),每次只使用其中一块。
  • 存活对象复制:将 From 空间的存活对象复制到 To 空间,并保持紧凑排列。
  • 清空 From 空间:复制完成后,直接清空 From 空间。
工作流程
  1. STW 标记 From 空间的存活对象。
  2. 将存活对象按顺序复制到 To 空间。
  3. 交换 From 和 To 空间的角色。
  4. 恢复应用线程。
优点
  • 无碎片:对象在 To 空间连续排列。
  • 高效回收:只需遍历存活对象,适合存活率低的场景。
缺点
  • 内存浪费:需预留一半内存作为复制空间,实际可用内存仅 50%。
  • 存活率高时效率低:若多数对象存活,复制成本高。
应用场景
  • 年轻代回收(如 Serial、ParNew、Parallel Scavenge 收集器)。
  • G1 的年轻代 Region 回收

四、分代收集算法(Generational Collection)

核心思想

基于对象的生命周期特性,将堆划分为不同区域(年轻代、老年代),对不同代采用不同算法:

  1. 年轻代:对象存活率低,使用复制算法
  2. 老年代:对象存活率高,使用标记-清除标记-整理算法。
分代依据
  • 弱分代假说(Weak Generational Hypothesis):绝大多数对象朝生夕死。
  • 强分代假说(Strong Generational Hypothesis):多次存活的对象倾向于继续存活。
工作流程
  1. 年轻代 Minor GC:频繁触发,使用复制算法回收 Eden 和 Survivor 区。
  2. 老年代 Major GC/Full GC:触发频率低,使用标记-清除或标记-整理算法。
应用场景
  • 所有现代 JVM 收集器的默认策略(如 CMS、G1、ZGC 等)。

五、增量收集算法(Incremental Collecting)

原理
  • 将垃圾回收过程分为多个小步骤,与应用线程交替执行。
  • 每次仅回收部分垃圾,减少单次 STW 时间。
优点
  • 降低延迟:每次暂停时间短,适合实时性要求高的场景。
缺点
  • 总体吞吐量下降:频繁切换线程导致额外开销。
  • 实现复杂:需处理应用线程与回收线程的交互。
应用场景
  • CMS 的并发标记阶段(并发执行,但需最终 STW 修正)。
  • Shenandoah 收集器(并发复制对象)。

六、分区收集算法(Region-Based)

原理
  • 将堆划分为多个独立区域(Region),优先回收垃圾比例高的区域(Garbage-First 原则)。
  • 结合分代思想,动态分配区域角色(Eden、Survivor、Old)。
优点
  • 可预测停顿:通过控制每次回收的区域数量,满足 MaxGCPauseMillis 目标。
  • 高效管理大堆:避免全堆扫描,减少 STW 时间。
应用场景
  • G1 收集器:分 Region 管理,混合回收年轻代和老年代。
  • ZGC/Shenandoah:基于类似思想,扩展为全堆并发回收。

七、算法对比与选型

算法优点缺点适用场景
标记-清除实现简单,无移动开销内存碎片,两次 STW老年代(CMS)
标记-整理无碎片,空间利用率高STW 时间长,移动开销大老年代(Serial Old)
复制无碎片,回收效率高内存浪费,存活率高时低效年轻代(所有分代收集器)
分代收集结合对象生命周期优化需维护分代结构所有现代收集器
增量收集低延迟吞吐量下降实时系统(Shenandoah)
分区收集可预测停顿,大堆友好元数据管理复杂G1、ZGC、Shenandoah

总结

JVM 的垃圾收集算法是内存管理的核心,不同算法在吞吐量延迟内存开销之间权衡。实际应用中,分代收集与分区算法(如 G1)成为主流,而 ZGC/Shenandoah 进一步通过并发和压缩技术突破停顿时间限制。选择算法需结合应用场景(如堆大小、延迟要求)及 JVM 版本特性。


以下以CMS和G1垃圾收集器的原理与工作流程举例:

CMS(Concurrent Mark-Sweep)收集器

设计目标
  • 低延迟:通过并发标记和清除减少停顿时间(STW),适用于对响应时间敏感的应用(如Web服务)。
  • 老年代专用:仅管理老年代,需与年轻代收集器(如ParNew)配合使用。

核心原理
  1. 标记-清除算法
    • 通过标记存活对象,直接清除未标记的垃圾对象,不进行内存整理,可能导致内存碎片。
  2. 并发执行
    • 大部分垃圾回收阶段与应用线程并发执行,减少STW时间。

工作流程(4个阶段)
  1. 初始标记(Initial Mark)

    • STW:短暂暂停,标记从GC Roots直接可达的对象(如栈引用、静态变量)。
    • 依赖年轻代回收:通常与年轻代的Minor GC同步触发,避免全堆扫描。
  2. 并发标记(Concurrent Mark)

    • 并发执行:遍历老年代对象图,标记所有存活对象(与应用线程并行)。
    • 可能漏标:并发阶段应用线程可能修改对象引用,需后续修正。
  3. 重新标记(Remark)

    • STW:修正并发标记期间因应用线程运行导致的标记变化(使用增量更新或原始快照算法)。
    • 时间较长:需处理所有变更,是CMS中最耗时的STW阶段。
  4. 并发清除(Concurrent Sweep)

    • 并发执行:清除未标记的垃圾对象,回收内存空间。
    • 不整理内存:清除后产生内存碎片,需定期Full GC(使用Serial Old)进行压缩。

关键问题
  • 内存碎片:长期运行后可能触发Full GC,导致长时间停顿。
  • 浮动垃圾:并发阶段新产生的垃圾需等到下次回收。
  • CPU竞争:并发阶段占用CPU资源,可能影响应用吞吐量。

G1(Garbage-First)收集器

设计目标
  • 平衡吞吐量与延迟:通过分Region和可预测停顿,适应大堆内存(4GB+)场景。
  • 全堆管理:统一管理年轻代和老年代,动态分配Region角色。

核心原理
  1. 分Region模型

    • 堆被划分为多个大小固定(1MB~32MB)的Region,每个Region可以是Eden、Survivor或Old类型。(堆/2048)
    • Humongous区域:存储大于Region 50%的大对象。
  2. 标记-整理算法

    • 通过复制存活对象到新Region,避免内存碎片。
  3. 停顿预测模型

    • 根据用户设定的MaxGCPauseMillis,优先回收垃圾比例高的Region(Garbage-First原则)。

工作流程(3种操作模式)

G1的回收过程分为三种操作:年轻代回收(Young GC)并发标记周期(Concurrent Marking Cycle)混合回收(Mixed GC)


1. 年轻代回收(Young GC)
  • STW:暂停所有应用线程,复制Eden和Survivor区的存活对象到新Survivor或Old Region。
  • 触发条件:Eden区占满时触发。

2. 并发标记周期(Concurrent Marking Cycle)
  1. 初始标记(Initial Mark)

    • STW:标记GC Roots直接可达的对象(与Young GC同步触发,复用Young GC的暂停)。
  2. 根区域扫描(Root Region Scan)

    • 扫描Survivor区(作为GC Roots的一部分),确保并发标记的正确性。
  3. 并发标记(Concurrent Mark)

    • 并发执行:遍历堆中所有存活对象,标记存活状态。
  4. 最终标记(Final Mark)

    • STW:处理SATB(Snapshot-At-The-Beginning)队列中的引用变更,确保标记准确性。
  5. 清除阶段(Cleanup)

    • 部分STW:统计各Region的垃圾比例,识别高价值回收区域。
    • 不回收内存:仅选择待回收的Region,为混合回收做准备。

3. 混合回收(Mixed GC)
  • STW:同时回收年轻代和部分老年代Region(根据垃圾比例选择)。
  • 多次执行:可能分多次回收,直到满足MaxGCPauseMillis目标。

关键优势
  • 内存整理:通过复制算法避免碎片。
  • 可预测停顿:动态调整回收的Region数量以满足停顿目标。
  • 大堆优化:分Region设计适合管理超大堆内存。

CMS与G1对比

特性CMSG1
堆结构传统分代(年轻代+老年代)分Region,逻辑分代
算法标记-清除(碎片需Full GC整理)标记-整理(复制算法,无碎片)
停顿控制不可预测通过MaxGCPauseMillis预测
适用场景中小堆,低延迟优先大堆(4GB+),平衡吞吐量和延迟
内存开销较高(Region元数据)
Full GC触发内存不足/碎片时触发Serial Old尽量避免,依赖并发周期
JDK支持已废弃(JDK 14移除)JDK 9+默认

总结

  • CMS:通过并发标记-清除减少停顿,适合中小堆且延迟敏感的场景,但面临碎片和Full GC风险。
  • G1:分Region模型和可预测停顿设计,适合大堆内存,平衡吞吐量与延迟,是JDK 9+的默认选择。

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

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

相关文章

如何为服务设置合理的线程数

1. 首先,要确定最大线程数的限制因素。通常,线程数量受限于内存、CPU和操作系统限制。比如,每个线程都需要一定的栈内存,默认情况下Java线程的栈大小是1MB(64位系统可能更大),所以如果内存不足&…

内容中台:元数据驱动管理新范式

元数据驱动智能管理中枢 现代企业内容管理正经历从碎片化存储向结构化治理的范式转变,元数据驱动机制在此过程中展现出核心枢纽价值。通过构建多维属性标签体系,Baklib等内容中台解决方案实现了对文本、音视频等数字资产的精准定义,其动态分…

在mac中设置环境变量

步骤一:打开终端 步骤二:输入printenv,查看当前已有的环境变量; 步骤三:输入:nano ~/.zshrc 打开环境变量编辑页面; 步骤四:输入新的变量:export DEEPSEEK_API_KEY&qu…

扩散模型的算法原理及其在图像生成领域的优势与创新

目录 一、引言 二、扩散模型的加噪过程 (一)前向扩散过程 (二)噪声调度策略 三、扩散模型的去噪过程 (一)反向扩散过程 (二)去噪网络架构 四、扩散模型的训练和推理机制 &am…

技术领域,有许多优秀的博客和网站

在技术领域,有许多优秀的博客和网站为开发者、工程师和技术爱好者提供了丰富的学习资源和行业动态。以下是一些常用的技术博客和网站,涵盖了编程、软件开发、数据科学、人工智能、网络安全等多个领域: 1. 综合技术博客 1.1 Medium 网址: ht…

mysql经典试题共34题

1、准备数据 -- drop drop table if exists dept; drop table if exists emp; drop table if exists salgrade;-- CREATE CREATE TABLE dept (deptno int NOT NULL COMMENT 部门编号,dname varchar(14) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMM…

2025 - GDB 盲调笔记--调试 “无调试符号“ “无调试信息“ 的三方程序

环境: arm64-ubuntu 相关:strace、ltrace、readelf、patchelf、strings、ldd -v 1). 使用 gdb 启动目标程序(不能直接用gdb启动的,可以先单独启动,再 gdb attach 强制调试) DIR_APP/opt/test gdb --args env LANGUAGE LD_LIBRA…

OCPP扩展机制与自定义功能开发:协议灵活性设计与实践 - 慧知开源充电桩平台

OCPP扩展机制与自定义功能开发:协议灵活性设计与实践 引言 OCPP作为开放协议,其核心价值在于平衡标准化与可扩展性。面对不同充电桩厂商的硬件差异、区域能源政策及定制化业务需求,OCPP通过**扩展点(Extension Points&#xff09…

【项目】nnUnetv2复现

作者提出一种nnUNet(no-new-Net)框架,基于原始的UNet(很小的修改),不去采用哪些新的结构,如相残差连接、dense连接、注意力机制等花里胡哨的东西。相反的,把重心放在:预处理(resampling和normalization)、训练(loss,optimizer设置、数据增广)、推理(patch-based…

代码随想录算法训练营第八天|Leetcode 151.翻转字符串里的单词 卡码网:55.右旋转字符串 字符串总结 双指针回顾

151.翻转字符串里的单词 建议:这道题目基本把 刚刚做过的字符串操作 都覆盖了,不过就算知道解题思路,本题代码并不容易写,要多练一练。 题目链接/文章讲解/视频讲解:代码随想录 我们这道题的思路是,先将整…

【计算机网络】计算机网络的性能指标——时延、时延带宽积、往返时延、信道利用率

计算机网络的性能指标 导读 大家好,很高兴又和大家见面啦!!! 在上一篇内容中我们介绍了计算机网络的三个性能指标——速率、带宽和吞吐量。用大白话来说就是:网速、最高网速和实时网速。 相信大家看到这三个词应该就…

Refreshtoken 前端 安全 前端安全方面

网络安全 前端不需要过硬的网络安全方面的知识,但是能够了解大多数的网络安全,并且可以进行简单的防御前两三个是需要的 介绍一下常见的安全问题,解决方式,和小的Demo,希望大家喜欢 网络安全汇总 XSSCSRF点击劫持SQL注入OS注入请求劫持DDOS 在我看来,前端可以了解并且防御前…

vue3框架的响应式依赖追踪机制

当存在一个响应式变量于视图中发生改变时会更新当前组件的所以视图显示,但是没有视图中不写这个响应式变量就就算修改该变量也不会修改视图,这是为什么?我们能否可以理解宽泛的理解为vue组件的更新就是视图的更新,单当视图中不存在…

C#核心(22)string

前言 我们在之前的学习中已经学习过了很多数字类型的数据结构,但一直没有讲解除了char以外的字符串相关的知识点,这也是我们继继承,封装,重载这些知识点之后要补充讲解的核心知识点。 你也发现了,其实在密封函数之后我们就已经开始进入更底层的方面为你讲解知识点了,这…

Spring Boot 本地缓存工具类设计与实现

在 Spring Boot 应用中,缓存是提升性能的重要手段之一。为了更方便地使用缓存,我们可以设计一套通用的本地缓存工具类,封装常见的缓存操作,简化开发流程。本文将详细介绍如何设计并实现一套 Spring Boot 本地缓存工具类&#xff0…

引领变革!北京爱悦诗科技有限公司荣获“GAS消费电子科创奖-产品创新奖”!

在2025年“GAS消费电子科创奖”评选中,北京爱悦诗科技有限公司提交的“aigo爱国者GS06”,在技术创新性、设计创新性、工艺创新性、智能化创新性及原创性五大维度均获得评委的高度认可,荣获“产品创新奖”。 这一奖项不仅是对爱悦诗在消费电子…

考研英语语法全攻略:从基础到长难句剖析​

引言 在考研英语的备考之旅中,语法犹如一座灯塔,为我们在浩瀚的英语知识海洋中指引方向。无论是阅读理解中复杂长难句的解读,还是写作时准确流畅表达的需求,扎实的语法基础都起着至关重要的作用。本文将结合有道考研语法基础入门课的相关内容,为大家全面梳理考研英语语法…

构建自己的AI客服【根据用户输入生成EL表达式】

要实现一个基于对话形式的AI客服系统,该系统能够提示用户输入必要的信息,并根据用户的输入生成相应的EL(Expression Language)表达式编排规则,您可以按照以下步骤进行设计和开发。本文将涵盖系统架构设计、关键技术选型…

【JavaWeb12】数据交换与异步请求:JSON与Ajax的绝妙搭配是否塑造了Web的交互革命?

文章目录 🌍一. 数据交换--JSON❄️1. JSON介绍❄️2. JSON 快速入门❄️3. JSON 对象和字符串对象转换❄️4. JSON 在 java 中使用❄️5. 代码演示 🌍二. 异步请求--Ajax❄️1. 基本介绍❄️2. JavaScript 原生 Ajax 请求❄️3. JQuery 的 Ajax 请求 &a…

解决CentOS 8.5被恶意扫描的问题

CentOS 8 官方仓库已停止维护(EOL),导致一些常用依赖包如fail2ban 无法正常安装。 完整解决方案: 一、问题根源 CentOS 8 官方仓库已停更:2021 年底 CentOS 8 停止维护,默认仓库的包可能无法满足依赖关系。EPEL 仓库兼容性:EPEL 仓库可能未适配 CentOS 8.5 的旧版本依赖…