news 2026/4/23 12:55:43

JVM垃圾回收(GC)核心原理全解析(从垃圾判断到调优实战)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
JVM垃圾回收(GC)核心原理全解析(从垃圾判断到调优实战)

JVM垃圾回收(GC)核心原理全解析(从垃圾判断到调优实战)

一、GC 的核心本质

GC(Garbage Collection)是 JVM 自动管理内存的核心机制,核心目标是:

  • 识别并回收堆内存中 “不再被使用的对象”,释放无用内存,避免内存溢出(OOM);
  • 无需程序员手动调用free/delete(对比 C/C++),降低内存泄漏风险;
  • 注意:GC 主要回收堆内存(99% 的场景),元空间(方法区)仅在 “无用类” 极少场景下回收,线程私有区域(栈、PC 寄存器)随线程销毁自动释放,无需 GC。

二、第一步:如何判断 “垃圾”(对象是否可回收)

GC 的前提是准确识别 “无用对象”,JVM 采用可达性分析算法,这是所有 GC 的基础逻辑:

1. 核心规则

GC Roots(垃圾回收根节点)为起点,遍历对象的引用链:

  • 若对象能通过引用链连接到 GC Roots →存活对象(不可回收);
  • 若对象与 GC Roots 无任何引用链 →垃圾对象(可回收)。

2. GC Roots 的常见类型(必须记)

只有以下类型的对象能作为 GC Roots,是判断存活的 “根”:

  • 虚拟机栈(方法栈帧)中局部变量表的对象引用(如main方法中demo变量);
  • 方法区(元空间)中静态变量 / 常量引用的对象(如static String str = new String());
  • 本地方法栈中 JNI(Native 方法)引用的对象;
  • JVM 内部的核心对象(如 Class 对象、ClassLoader、线程对象)。

3. 补充:引用类型(影响 GC 判断)

Java 的引用分为 4 种,直接决定对象的回收优先级(从强到弱):

引用类型特点GC 行为
强引用(Strong)最普通的引用(如Object obj = new Object()只要强引用存在,对象绝对不回收
软引用(Soft)SoftReference包装,用于缓存场景内存不足时(即将 OOM)才会回收
弱引用(Weak)WeakReference包装,用于临时缓存每次 GC 都会回收(无论内存是否充足)
虚引用(Phantom)PhantomReference包装,仅用于跟踪对象回收,不能获取对象本身随时回收,回收前会触发引用队列通知

三、第二步:垃圾回收的核心流程(分代回收)

JVM 将堆内存分为新生代老年代(基于 “对象存活时间” 的分代假设:大部分对象朝生夕死),采用 “分代回收” 策略提升效率,这是 GC 的核心优化思路。

1. 堆的分代结构(JDK8+)

补充说明
  • 分代依据:基于“大部分对象朝生夕死”的假设,分代回收提升GC效率;
  • Minor GC:新生代内存不足触发,仅回收新生代,复制算法,速度快、频率高;
  • Survivor(幸存者) 交换机制:Minor GC后存活对象复制到空的Survivor区,年龄计数器+1,年龄达标(默认15)进入老年代;
  • Major/Full GC:老年代内存不足触发,回收老年代+新生代,标记-整理算法,速度慢、频率低;
  • 参数调整:可通过-XX:NewRatio调整新生代/老年代比例(如 -XX:NewRatio=2 → 1:2),-XX:SurvivorRatio调整Eden/Survivor比例(默认8)。

2. 分代回收的完整流程(核心)

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

触发条件:Eden 区(伊甸园)内存不足(新对象分配失败);

回收流程

  1. 新对象优先分配到 Eden 区;
  2. Eden 区满时,触发 Minor GC,标记 Eden+Survivor0 中存活的对象;
  3. 存活对象复制到 Survivor1 区,同时给对象的 “年龄计数器”+1;
  4. 清空 Eden+Survivor0 区,交换 Survivor0/Survivor1 的角色(下次 GC 用新的 Survivor0);
  5. 若 Survivor1 空间不足,存活对象直接进入老年代;

特点:频率高(每秒可能多次)、速度快(新生代空间小)、STW(暂停用户线程)时间短。

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

触发条件:

  1. 老年代内存不足;
  2. Minor GC 后存活对象过多,无法放入老年代;
  3. 元空间(方法区)不足;
  4. 手动调用System.gc()(仅建议,JVM 可忽略);

回收流程:

  1. 标记老年代中存活的对象;
  2. 回收无用对象,整理内存碎片(不同回收器策略不同);
  3. 通常会连带回收新生代(即 Full GC);

特点:频率低(几分钟 / 几小时一次)、速度慢(老年代空间大)、STW 时间长(影响程序响应)。

3. 核心优化点:分代回收的意义

  • 新生代对象 “朝生夕死”,用复制算法(效率高),仅需复制少量存活对象;
  • 老年代对象存活时间长,用标记 - 清除 / 标记 - 整理算法(避免内存碎片);
  • 分代回收避免了 “全堆扫描”,大幅提升 GC 效率。
补:

什么是Full GC?

Full GC(Full Garbage Collection,全量垃圾回收)就是对 JVM 堆内存的「新生代 + 老年代」进行全区域、一次性的垃圾回收,这是 JVM 垃圾回收中最重量级的操作,同时在 JDK 8 及以前,还会连带回收方法区(永久代);JDK 8 以后则回收元空间(部分场景)。

什么时候会触发Full GC呢?

(1) 老年代内存空间不足(最核心、最常见)

新生代对象经过多次 Minor GC 后仍存活(达到晋升阈值),会被转移到老年代;如果程序创建大对象(直接进入老年代)、老年代中存活对象过多,导致老年代剩余可用内存无法容纳新进入的对象 / 数据,就会触发 Full GC,尝试回收老年代的垃圾空间来腾出内存。

(2) 方法区 / 元空间内存耗尽

JDK 8 及以前:方法区(永久代)存储类信息、常量、静态变量等,当加载的类过多、常量池过大导致永久代满,触发 Full GC;

JDK 8 以后:永久代被元空间替代(位于直接内存),若元空间未设置上限或上限不足,内存耗尽时也会触发 Full GC(部分 HotSpot 版本行为)。

(4) Minor GC 后的晋升失败(Promotion Failure)

Minor GC 回收新生代后,会将存活对象晋升到老年代,但此时老年代没有足够的连续内存容纳这些晋升对象(即使老年代总剩余内存足够,碎片过多也会导致),就会触发 Full GC:先回收老年代的垃圾并整理内存(消除碎片),再尝试接收新生代的晋升对象。

(4) 显式调用 System.gc () 方法

代码中直接调用System.gc()时,会向 JVM 发送 “垃圾回收建议”,多数 HotSpot 版本(默认配置)会响应这个建议,触发 Full GC(注意:这只是建议,JVM 可忽略,但日常开发中基本都会执行,开发的时候使用,容易导致程序卡顿)。

什么是Minor GC?

Minor GC(新生代垃圾回收):仅针对 JVM 堆内存新生代(Eden 区 + Survivor 区)执行的局部、轻量级垃圾回收,不会涉及老年代,是 JVM 中执行频率最高的 GC 操作。

什么时候触发Minor GC呢?

新生代的 Eden 区内存被完全占满,无法再为新创建的对象分配内存时,立即触发 Minor GC


四、第三步:垃圾回收算法(底层实现)

1.复制算法(Copying Algorithm)
核心定位

新生代(Eden+Survivor)的核心回收算法,专门针对 “对象朝生夕死、存活数量少” 的场景。

具体执行步骤
Step 1:内存划分 → 将目标内存(新生代)划分为「可用区」和「空闲区」(优化后用Eden+2个Survivor,而非严格1:1); Step 2:标记存活 → 以GC Roots为根,标记可用区中所有存活的对象; Step 3:复制对象 → 将所有存活对象按顺序复制到空闲区(紧凑排列,无碎片); Step 4:清空原区 → 彻底清空原来的可用区,将其转为新的空闲区; Step 5:角色互换 → 原空闲区变为新的可用区,原可用区变为空闲区,等待下一次GC。

流程示意图:

2.标记 - 清除算法(Mark-Sweep Algorithm)
核心定位

早期老年代使用的算法,适合 “对象存活多、回收少” 的场景,但缺点明显,现已被标记 - 整理替代。

具体执行步骤
Step 1:标记阶段 → 从GC Roots出发,遍历所有对象,标记出存活的对象(未标记的即为垃圾); Step 2:清除阶段 → 遍历整个内存区域,直接清除所有未被标记的垃圾对象; Step 3:完成回收 → 仅释放垃圾对象的内存,存活对象保持原有位置不变。

流程示意图:

3. 标记 - 整理算法(Mark-Compact Algorithm)
核心定位

现代老年代的主流算法,解决了标记 - 清除的 “内存碎片” 问题,是老年代的最优选择。

具体执行步骤
Step 1:标记阶段 → 与标记-清除一致,从GC Roots出发标记所有存活对象; Step 2:整理阶段 → 将所有存活对象向内存的一端紧凑移动(按顺序排列); Step 3:清除阶段 → 直接清除“存活对象边界外”的所有内存区域(批量释放,无需逐个清理); Step 4:完成回收 → 内存中存活对象紧凑排列,无碎片,空闲内存集中在一端。

流程示意图:

3.3种回收算法表:

不同区域采用不同的回收算法,核心有 3 种:

算法类型核心步骤优点缺点适用区域
复制算法1. 划分内存为 2 块;2. 标记存活对象;3. 复制到另一块;4. 清空原块效率高、无内存碎片浪费 50% 内存(优化后用 Survivor)新生代(Eden+Survivor)
标记 - 清除算法1. 标记存活对象;2. 直接清除无用对象不浪费内存效率低、产生内存碎片老年代(早期)
标记 - 整理算法1. 标记存活对象;2. 将存活对象向一端移动;3. 清除边界外的所有内存无内存碎片、不浪费内存效率较低(需移动对象)老年代(主流)

五、第四步:常见垃圾回收器(落地实现)

回收算法是 “理论”,回收器是 “落地实现”,不同回收器适配不同应用场景(HotSpot 虚拟机):

1. 核心回收器对比(面试重点)

以下是 JDK 中最常用的收集器,包含核心特点、算法、适用场景,是学习和面试的重点:

收集器回收范围核心算法线程模式核心特点适用场景
SerialGC新生代复制算法串行单线程、STW 短、效率低客户端 / 单核 / 低配置程序(如桌面应用)
ParallelGC新生代复制算法并行多线程、吞吐量优先、STW 略长后端服务 / 批处理 / 数据计算(高吞吐量)
SerialOldGC老年代标记 - 整理算法串行单线程、与 SerialGC 搭配,效率低客户端 / 低配置程序
ParallelOldGC老年代标记 - 整理算法并行多线程、与 ParallelGC 搭配,吞吐量优先高吞吐量场景(与 ParallelGC 组合)
CMS老年代标记 - 清除算法并发低延迟、大部分阶段并发、有内存碎片Web 服务 / 响应时间敏感场景(如电商)
G1GC全堆(新生代 + 老年代)复制 + 标记 - 整理并行 + 并发分区回收、可预测 STW、无内存碎片JDK8 + 默认服务器端收集器、通用场景
ZGC全堆复制算法并发近乎无 STW(<10ms)、支持超大堆、低延迟高并发 / 低延迟 / 超大堆场景(JDK11+)

补:什么是STW?

STW(Stop The World,全局停顿 / 停止所有业务线程)是 JVM 执行垃圾回收时触发的「全局线程暂停机制」:当 JVM 开始执行 GC 操作(无论 Minor GC 还是 Full GC),会立即暂停当前进程中所有正在运行的业务线程(用户请求处理、数据计算、接口调用等业务逻辑全部停止),直到 GC 操作完全执行完毕,才会恢复所有业务线程的运行。

2. 核心回收器组合(JVM 默认配置)

垃圾收集器的组合规则

除全堆收集器(G1/ZGC)可单独使用外,新生代收集器和老年代收集器必须固定组合,JVM 不支持随意搭配,以下是 JDK 中主流的合法组合:

新生代收集器老年代收集器组合名称JDK 默认配置核心优势
SerialGCSerialOldGC串行收集组合JDK 客户端默认资源消耗低、实现简单
ParallelGCParallelOldGC并行收集组合JDK8 服务器端默认高吞吐量、适合批处理
ParallelGCCMS并行 + 并发组合手动配置兼顾吞吐量和低延迟
G1GC-(单独使用)全堆收集器JDK9 + 默认可预测 STW、通用场景适配
ZGC-(单独使用)全堆收集器手动配置低延迟、超大堆支持

注意:CMS 是唯一的老年代并发收集器,其新生代只能搭配 ParallelGC,无法与 SerialGC 组合。


六、GC 的关键指标(调优核心)

理解 GC 调优需关注 3 个核心指标:

  1. 吞吐量:程序运行时间 / (程序运行时间 + GC 时间) → 越高越好(如 99%);
  2. 延迟:GC 导致的 STW 时间 → 越低越好(如 < 100ms);
  3. 内存占用:JVM 使用的内存大小 → 合理即可(避免过大 / 过小)。

注:吞吐量和延迟是 “鱼和熊掌”,调优需根据业务场景取舍(如批处理优先吞吐量,Web 服务优先低延迟)。


七、GC 调优的核心思路(实用技巧)

  1. 优先调优堆内存:
    • 设置初始堆-Xms= 最大堆-Xmx(避免堆动态扩容触发 GC);
    • 新生代比例-XX:NewRatio(如-XX:NewRatio=2→ 新生代:老年代 = 1:2);
  2. 选择合适的回收器:
    • 高吞吐量:ParallelGC + ParallelOldGC;
    • 低延迟:G1GC/ZGC;
  3. 监控 GC 状态:
    • jstat -gc <进程ID>查看 GC 次数 / 时间;
    • jvisualvm/Arthas可视化监控 GC;
  4. 避免手动触发 GCSystem.gc()(会向 JVM 发送 “垃圾回收建议”)仅为建议,JVM 可能忽略,且易触发 Full GC。

总结

  1. GC 的核心是可达性分析算法(以 GC Roots 为根判断垃圾),结合分代回收策略提升效率;
  2. 新生代用复制算法(Minor GC),老年代用标记 - 整理算法(Major/Full GC);
  3. 常见回收器中,G1 是 JDK8 + 主流,ZGC/Shenandoah 适配低延迟场景,调优需平衡吞吐量和延迟。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/15 14:44:50

用AI教材写作工具,低查重快速生成高质量专业教材

教材创作的艰辛与AI工具的助力 教材的初稿终于完成&#xff0c;后续的修改和优化过程简直像是一场“折磨”&#xff01;为了确保文章逻辑严谨、知识点准确&#xff0c;我必须一遍又一遍地仔细阅读&#xff0c;这无疑是个耗时的工作。当需要调整某个章节时&#xff0c;竟然会影…

作者头像 李华
网站建设 2026/4/23 11:27:17

SpringBoot外语学习论坛系统任务书

SpringBoot外语学习论坛系统任务书 一、任务背景 随着全球化进程加快&#xff0c;外语学习需求日益增长&#xff0c;传统线下学习模式受时间、空间限制&#xff0c;难以满足学习者互动交流、资源共享的需求。当前各类外语学习平台多侧重单一知识点讲解&#xff0c;缺乏便捷的用…

作者头像 李华
网站建设 2026/4/19 18:37:55

最推荐的JAVA开源物联网平台

物联网平台 - Thinglinks-iot ## &#x1f31f; 项目简介 一个功能完备、高可扩展的物联网平台&#xff0c;用最少的代码接入设备&#xff0c;基于Ruoyi-vue框架&#xff0c;支持Mysql和pgsql双版本&#xff0c;集成mybatis-plus&#xff0c;集成TCP、MQTT、UDP、CoAP、HTTP、…

作者头像 李华