当前位置: 首页 > news >正文

JVM的垃圾回收机制(一次完整的GC流程)

一、GC 触发前提

GC 由 JVM 自动触发,核心触发条件:

  1. 新生代空间不足:对象创建时若 Eden 区满,触发 Minor GC(仅回收新生代);
  2. 老年代空间不足:Minor GC 后对象晋升到老年代,若老年代满,触发 Major GC/Full GC(回收老年代 + 新生代,可能含元空间);
  3. 元空间不足:类加载时元空间(存储类信息、常量等)满,触发元空间清理;
  4. 主动调用:代码中调用 System.gc()(JVM 可忽略,仅为建议)。

二、完整 GC 流程(分代收集)

阶段 1:Minor GC(新生代回收)

新生代分为 Eden 区(80%)和两个 Survivor 区(S0、S1,各 10%),对象优先在 Eden 区创建,流程如下:

  1. 对象分配:新对象先存入 Eden 区,当 Eden 区满时,触发 Minor GC;
  2. 存活对象标记:用 可达性分析法 标记 Eden 区和 S0 区中 “存活的对象”(从 GC Roots 可达的对象);
  3. 存活对象复制:将标记出的存活对象,按年龄(每经历一次 Minor GC 年龄 + 1)复制到 S1 区:
    • 年龄未达阈值(默认 15):直接复制到 S1 区;
    • 年龄达阈值:晋升到 老年代(大对象可能直接进入老年代,避免频繁复制);
  4. 清空无效对象:清空 Eden 区和 S0 区的无效对象(未被标记的垃圾);
  5. 角色互换:S0 和 S1 区互换角色(下次 Minor GC 时,S1 作为 “from 区”,原 S0 作为 “to 区”),保证每次只有一个 Survivor 区存存活对象。

特点:Minor GC 频率高、耗时短(新生代对象存活时间短,复制成本低),采用 复制算法

阶段 2:Major GC/Full GC(老年代 + 新生代回收)

当老年代空间不足(如 Minor GC 后晋升的对象超过老年代剩余空间),触发 Major GC(有时也叫 Full GC,若同时回收新生代则为 Full GC),流程如下:

  1. 全局标记:用 可达性分析法 标记老年代、新生代中所有存活对象(GC Roots 遍历全堆);
  2. 清除无效对象
    • 老年代采用 标记 - 清除算法 或 标记 - 整理算法
      • 标记 - 清除:直接删除未标记的垃圾,效率高但会产生内存碎片;
      • 标记 - 整理:将存活对象向一端移动,然后清除边界外的垃圾,无碎片但耗时更长;
    • 新生代同步执行一次 Minor GC(复制算法),清空无效对象;
  3. 内存整理(可选):若老年代用标记 - 整理算法,移动存活对象后,更新对象引用地址(避免空指针);
  4. 元空间清理:若元空间(永久代)满,清理未使用的类信息(如类加载器回收、类无引用),释放元空间内存。(注:元空间内存不足时采用的是FullGC算法)
阶段 3:STW(Stop The World)与并发优化

GC 执行时会暂停应用线程(STW),避免线程操作与 GC 冲突,主流 JVM 通过优化减少 STW 时间:

  1. Minor GC 的 STW:仅暂停线程短暂时间(毫秒级),复制存活对象时锁定新生代;
  2. 并发 GC(如 G1、ZGC):将标记阶段拆分为 “初始标记”“并发标记”“最终标记”,仅初始和最终标记需 STW,并发标记阶段与应用线程并行,大幅缩短 STW 时间。

三、完整流程总结(简化版)

  1. 触发:Eden 区满 → 触发 Minor GC;老年代满 → 触发 Major/Full GC;
  2. Minor GC:标记 Eden+S0 存活对象 → 复制到 S1(或晋升老年代)→ 清空 Eden+S0 → S0/S1 互换;
  3. Major/Full GC:全堆标记存活对象 → 老年代清除 / 整理垃圾 + 新生代 Minor GC → 元空间清理;
  4. 恢复:STW 结束,应用线程继续执行,内存分配恢复。

扩展与补充:

1、Minor GC和Major GC/Full GC的区别

Minor GC 快
新生代用复制算法

Major GC 慢
老年代用标记 - 清除 / 整理算法

Full GC 最慢
需同时处理新生代和老年代,STW 时间可能长达几秒,严重影响应用响应性

2、标记 - 清除算法 或 标记 - 整理算法在老年代什么时候执行?

  • 标记 - 清除:老年代中多用于低延迟收集器(如 CMS),优先保证回收速度,通过定期整理缓解碎片。
  • 标记 - 整理:老年代中多用于吞吐量优先或稳定性要求高的收集器(如 Serial Old、Parallel Old、G1),通过消除碎片保证长期内存分配效率。

3、元空间与永生代的区别?

JDK 8 用元空间替代永久代,主要差异如下:

特性永久代(JDK 7 及之前)元空间(JDK 8 及之后)
内存区域属于 JVM 堆内存的一部分属于本地内存(Native Memory)
大小限制默认有固定大小(可通过 -XX:PermSize 和 -XX:MaxPermSize 调整)默认无上限(受本地内存大小限制,可通过 -XX:MaxMetaspaceSize 限制)
内存溢出风险容易因类过多导致 PermGen OOM内存溢出风险降低(除非本地内存耗尽)
垃圾回收依赖 JVM 堆的 GC 机制独立的元空间 GC 机制,当元空间不足时触发

http://www.dtcms.com/a/389192.html

相关文章:

  • 拥抱新一代 Web 3D 引擎,Three.js 项目快速升级 Galacean 指南
  • Linux 内核裁剪与功能扩展实验报告
  • Qt QVCandlestickModelMapper详解
  • LeetCode:20.旋转图像
  • 网络协议深度解析:从OSI七层模型到现代互联网通信的技术实战
  • 慈明学校以孝治家阳光家庭教育中心 学以致用践行以孝治家幸福万家
  • 开心实习之 深度学习之多层感知机
  • 前端构造数据格式及表格添加行
  • 深度学习-神经网络(上篇)
  • 【脑电分析系列】第18篇:传统机器学习在EEG中的应用 — SVM、LDA、随机森林等分类器
  • 理解长短期记忆神经网络(LSTM)
  • Kurt-Blender零基础教程:第2章:建模篇——第1节:点线面的选择与控制与十大建模操作
  • 鸿蒙5.0应用开发——V2装饰器@Monitor的使用
  • 八、Java-XML
  • 计算机在医疗领域应用的独特技术问题分析
  • HTB Intentions writeup(SQL二次注入也是注入)
  • 第一章 预训练:让模型“博闻强识”
  • 【数组】求两个匀速运动质点的相交或最小距离
  • 新手向:Python爬虫原理详解,从零开始的网络数据采集指南
  • OKZOO进军HealthFi:承接AIoT,引领Health-to-Earn
  • Halcon 相机标定
  • 腾讯混元发布集成翻译模型Hunyuan-MT-Chimera-7B,已开放体验
  • mybatis-plus扩展
  • 从x.ai到VSCode:一个AI编程助手的意外之旅
  • SQLite vs MySQL:核心SQL语法差异全面解析
  • 【每日算法】两数相加 LeetCode
  • ActiveMQ底层原理与性能优化
  • Ceph IO流程分段上传(1)——InitMultipart
  • 大数据毕业设计选题推荐-基于大数据的农作物产量数据分析与可视化系统-Hadoop-Spark-数据可视化-BigData
  • 【回归之作】学校实训作业:Day04面向对象思想编程