JVM 垃圾收集器 (GC) 完整版

一、GC 核心基础(必背)

1. 为什么需要 GC?

  • Java 对象在堆内存 创建,不回收会导致 OOM(内存溢出)
  • GC 自动回收无用对象内存,避免内存泄漏,保证程序长期运行
  • 对比 C/C++ 手动管理内存:GC 更安全,但会产生 STW(停顿)

2. 回收什么?------ 无用对象判定

JVM 只用 可达性分析算法,不用引用计数。

表格

算法 原理 优点 缺点
引用计数 对象被引用 + 1,失效 - 1,为 0 则回收 简单高效 无法解决循环引用
可达性分析 从 GC Roots 遍历,不可达对象判定为垃圾 安全准确,JVM 默认 实现稍复杂

GC Roots 固定 4 类

  1. 虚拟机栈局部变量引用
  2. 方法区静态属性引用
  3. 方法区常量引用
  4. 本地方法栈 JNI 引用

3. 怎么回收?------ 三大基础算法

所有 GC 都基于这 3 步,只是实现不同:

  1. 标记:标记存活 / 垃圾对象
  2. 清除:回收垃圾内存(会产生碎片)
  3. 整理:移动对象,消除内存碎片

核心矛盾 标记 / 清除 / 整理必须 STW(Stop The World)暂停用户线程 垃圾收集器 = 在 回收效率、内存碎片、停顿时间 之间做平衡


二、JVM 内存分代模型(核心)

堆内存 = 年轻代 + 老年代元空间不在堆内,本文不重点讲。

表格

分代 对象特点 回收频率 核心需求
年轻代 新对象、生命周期短 极高(Minor GC) 回收快、停顿短
老年代 长期存活、大对象 低(Full GC) 无碎片、效率稳

三、7 大垃圾收集器 超详细对比(面试必考)

分类总览

  • 年轻代:Serial、ParNew
  • 老年代:Serial Old、Parallel Old
  • 整堆回收:CMS、G1、ZGC/Shenandoah

3.1 年轻代收集器

① Serial GC(串行)

  • 单线程回收,全程 STW
  • 算法:复制算法
  • 搭配:老年代 Serial Old
  • 优点:简单、轻量、无线程开销
  • 缺点:停顿极长,不利用多核
  • 场景:堆内存 <1GB、嵌入式、桌面应用
  • 参数:-XX:+UseSerialGC

② ParNew GC(并行)

  • Serial 多线程版本
  • 算法:复制算法
  • 唯一能和 CMS 配合的年轻代收集器
  • 优点:多核下停顿更短
  • 缺点:仍有 STW,单核不如 Serial
  • 场景:多核服务器 + CMS 组合
  • 参数:-XX:+UseParNewGC

3.2 老年代收集器

① Serial Old(串行)

  • 单线程、标记 - 整理算法
  • 优点:无碎片、实现简单
  • 缺点:停顿极长
  • 场景:小内存、Serial GC 配套使用

② Parallel Old(并行)

  • JDK8 默认老年代收集器
  • 多线程、标记 - 整理算法
  • 搭配:Parallel Scavenge(年轻代)
  • 目标:高吞吐量
  • 优点:多核高效、无碎片
  • 缺点:停顿时间不可控
  • 场景:后台计算、批处理、数据任务
  • 参数:-XX:+UseParallelOldGC

3.3 整堆收集器(最重要)

① CMS GC(并发标记清除)

  • 目标:低延迟
  • 算法:标记 - 清除(不整理,会产生碎片)
  • JDK9 废弃,JDK14 移除

4 阶段(2 段 STW + 2 段并发)

  1. 初始标记(STW,极快)
  2. 并发标记(和用户线程一起跑)
  3. 重新标记(STW,修正标记)
  4. 并发清除(和用户线程一起跑)

优点

  • 停顿极短
  • 并发回收,不阻塞业务

缺点(必背)

  1. 内存碎片(最致命)
  2. 占用 CPU,降低吞吐量
  3. 无法处理浮动垃圾
  4. concurrent mode failure 会退化为 Serial Old

场景 :Web 接口、低延迟要求高的服务参数-XX:+UseConcMarkSweepGC


② G1 GC(Garbage-First)

  • JDK9+ 默认收集器
  • 目前生产环境首选
  • 设计:分区内存(Region),打破固定分代
  • 算法:标记 - 整理 + 复制
  • 目标:兼顾吞吐量 + 低延迟

核心流程

  1. 初始标记(STW)
  2. 并发标记
  3. 最终标记(STW)
  4. 筛选回收(STW,优先回收垃圾最多的 Region)
  5. 并发清理

优点(必背)

  • 可控制停顿时间
  • 无内存碎片
  • 支持大堆(8GB~100GB)
  • 动态调整年轻 / 老年代

缺点

  • 占额外内存
  • CPU 要求高

场景 :微服务、分布式、大型 Web、通用服务器参数-XX:+UseG1GC


③ ZGC / Shenandoah GC(新一代超低延迟)

  • JDK11+ ZGC(官方主推)
  • JDK12+ Shenandoah(OpenJDK)
  • 停顿时间:微秒级(<10ms → <0.01ms)
  • 支持 TB 级堆内存
  • 几乎全程并发,标记 / 复制都不 STW

优点

  • 延迟极致
  • 堆越大优势越明显
  • 无碎片

场景 :金融交易、实时计算、超大堆服务参数

  • ZGC:-XX:+UseZGC
  • Shenandoah:-XX:+UseShenandoahGC

四、垃圾收集器 最强对比表

表格

收集器 类型 算法 优点 缺点 适用场景 JDK 默认
Serial 年轻代 复制 简单轻量 单线程、停顿长 小内存、嵌入式 -
ParNew 年轻代 复制 多核并行 停顿不可控 配合 CMS -
SerialOld 老年代 标记 - 整理 无碎片 停顿极长 小内存 -
ParallelOld 老年代 标记 - 整理 高吞吐 停顿较长 后台任务 JDK8
CMS 整堆 标记 - 清除 低延迟 内存碎片 Web 服务 废弃
G1 整堆 标记 - 整理 + 复制 均衡、无碎片 占内存 通用生产 JDK9+
ZGC 整堆 染色指针 微秒级停顿 吞吐量略低 低延迟大堆 JDK17+

五、实战选型指南(直接照抄用)

1. 优先用 JDK 默认

  • JDK8:Parallel + Parallel Old(吞吐量优先)
  • JDK9+:G1(通用首选)

2. 按业务场景选

  • 低延迟优先 (Web / 接口 / 秒杀)
    • 堆 <16G → G1
    • 堆 ≥16G → ZGC
    • JDK8 → CMS
  • 吞吐量优先(批处理 / 计算任务)→ Parallel + Parallel Old
  • 小内存(<1GB)→ Serial + Serial Old
  • 超大堆(≥32GB)→ ZGC(JDK11+)

3. 避坑提醒

  • 不要盲目追求低延迟
  • 不要乱调 GC 参数
  • CMS 已废弃,一律用 G1 替代

六、终极总结(一句话背会)

  1. Serial:单线程、小内存、简单
  2. Parallel:多线程、高吞吐、后台任务
  3. CMS:低延迟、有碎片、已废弃
  4. G1 :均衡通用、无碎片、生产首选
  5. ZGC:极致低延迟、未来趋势
相关推荐
wuqingshun3141592 小时前
说一下@RequestBody和@ResponseBody的区别?
java·开发语言·jvm
2401_8747325310 小时前
为你的Python脚本添加图形界面(GUI)
jvm·数据库·python
cm65432015 小时前
用Python破解简单的替换密码
jvm·数据库·python
Oueii16 小时前
掌握Python魔法方法(Magic Methods)
jvm·数据库·python
2501_9083298517 小时前
使用Python自动收发邮件
jvm·数据库·python
2501_9083298517 小时前
NumPy入门:高性能科学计算的基础
jvm·数据库·python
杰克尼17 小时前
知识点总结--02(java基础部分)
java·开发语言·jvm
2401_8747325318 小时前
Python Web爬虫入门:使用Requests和BeautifulSoup
jvm·数据库·python