JVM 垃圾回收(GC)详解
·
垃圾回收(Garbage Collection,GC)是 JVM 核心能力之一,其核心目标是自动识别并回收堆中不再被使用的对象内存,避免内存泄漏和溢出,无需程序员手动管理内存。下面从「回收核心问题、垃圾判定算法、回收器分类、核心回收流程、调优思路」五个维度全面解析。
一、GC 核心问题:哪些对象需要回收?
GC 的第一步是判定「死亡对象」(不再被使用的对象),主要有两种核心算法:
1. 引用计数法(已淘汰)
- 原理:给每个对象分配一个引用计数器,有引用指向时计数器 + 1,引用失效时 - 1;计数器为 0 则判定为死亡对象。
- 缺陷:无法解决「循环引用」问题(如 A 引用 B,B 引用 A,两者无外部引用,但计数器均不为 0),因此 HotSpot 虚拟机未采用该算法。
2. 可达性分析算法(主流)
-
原理:以「GC Roots」为起点,向下遍历所有引用链;若对象不在任何引用链上(不可达),则判定为可回收对象。
-
GC Roots 包含以下对象:
- 虚拟机栈(局部变量表)中引用的对象;
- 方法区中类静态属性引用的对象;
- 方法区中常量引用的对象;
- 本地方法栈中 Native 方法引用的对象;
- JVM 内部的核心对象(如锁对象、系统类加载器)。
-
引用类型补充:JDK 1.2 后将引用分为 4 种,影响对象回收时机:
表格
引用类型 特点 回收时机 强引用(默认) Object obj = new Object(),最普通的引用只有强引用失效时才会回收 软引用 SoftReference,用于缓存内存不足时(OOM 前)才会回收 弱引用 WeakReference,用于临时缓存下次 GC 时一定会回收 虚引用 PhantomReference,仅用于跟踪对象回收,必须配合引用队列使用随时可能回收
二、GC 核心区域:堆的分代回收
GC 主要针对堆内存,堆分为「新生代」和「老年代」(分代回收思想),不同区域采用不同回收策略:
1. 堆的分代结构

- 新生代:存储新创建的对象,对象存活率低(大部分对象创建后很快失效),采用「复制算法」(效率高)。
- 老年代:存储新生代中存活多次 GC 仍未被回收的对象,对象存活率高,采用「标记 - 清除 / 标记 - 整理算法」。
2. 核心回收算法
表格
| 算法类型 | 原理 | 优点 | 缺点 | 适用区域 |
|---|---|---|---|---|
| 复制算法 | 将内存分为两块,只用一块;GC 时将存活对象复制到另一块,清空原区域 | 无内存碎片,效率高 | 内存利用率低(仅 50%) | 新生代(Eden/S) |
| 标记 - 清除算法 | 标记存活对象,直接清除未标记对象 | 内存利用率高 | 产生内存碎片,后续大对象分配困难 | 老年代(辅助) |
| 标记 - 整理算法 | 标记存活对象,将存活对象移动到内存一端,清空另一端 | 无内存碎片,利用率高 | 移动对象开销大 | 老年代(主流) |
三、GC 类型与执行流程
根据回收区域和频率,GC 分为 3 类,执行流程有明确优先级:
1. Minor GC(新生代 GC)
- 触发条件:Eden 区满时触发(最频繁,毫秒级完成)。
- 执行流程:
- Eden 区满,触发 Minor GC,标记 Eden + S0 区的存活对象;
- 将存活对象复制到 S1 区,清空 Eden + S0 区;
- 下次 GC 时,S0 和 S1 角色互换(空的 Survivor 区作为目标);
- 若对象存活次数达到阈值(默认 15),则晋升到老年代。
- 特点:速度快,暂停时间短(STW 时间短)。
2. Major GC(老年代 GC)
- 触发条件:老年代空间不足时触发(频率低)。
- 执行流程:
- 对老年代执行「标记 - 整理算法」,清理死亡对象并整理内存;
- 通常伴随一次 Minor GC(先回收新生代,减少老年代晋升压力)。
- 特点:耗时久(秒级),STW(Stop The World)时间长,影响应用响应。
3. Full GC(全局 GC)
- 触发条件:
- 老年代满 + 新生代满;
- 元空间(Metaspace)满;
- 调用
System.gc()(建议性调用,JVM 不一定执行); - CMS 回收器出现「Concurrent Mode Failure」。
- 执行流程:回收新生代 + 老年代 + 元空间,是最耗时的 GC。
- 优化目标:尽可能避免 Full GC。
四、主流垃圾回收器(JDK 8/11 常用)
垃圾回收器是 GC 算法的具体实现,不同回收器适用于不同场景,HotSpot 虚拟机的核心回收器如下:
1. Serial 回收器(串行回收)
- 原理:单线程执行 GC,回收时暂停所有用户线程(STW)。
- 适用区域:新生代(复制算法)+ 老年代(标记 - 整理)。
- 特点:简单高效,内存占用少;但 STW 时间长,仅适用于单核心、小内存应用(如桌面程序)。
- 参数:
-XX:+UseSerialGC(开启串行回收器)。
2. Parallel Scavenge + Parallel Old(并行回收)
- 原理:多线程执行 GC,新生代用复制算法,老年代用标记 - 整理。
- 核心目标:「吞吐量优先」(吞吐量 = 程序运行时间 / (程序运行时间 + GC 时间))。
- 特点:多线程 GC 提升效率,STW 时间比 Serial 短;适用于后台运算、批量处理(如大数据任务)。
- 参数:
-XX:+UseParallelGC(新生代并行回收);-XX:+UseParallelOldGC(老年代并行回收);-XX:MaxGCPauseMillis(设置最大 GC 暂停时间);-XX:GCTimeRatio(设置吞吐量比例,默认 99)。
3. CMS 回收器(并发标记清除)
- 原理:老年代回收器,以「低延迟」为目标,分为 4 步:
- 初始标记(STW):标记 GC Roots 直接引用的对象(快);
- 并发标记:遍历引用链,标记存活对象(与用户线程并行,无 STW);
- 重新标记(STW):修正并发标记期间的对象状态(快);
- 并发清除:清除死亡对象(与用户线程并行)。
- 特点:STW 时间极短,适用于高响应要求的应用(如 Web 服务);但会产生内存碎片,且占用 CPU 资源(与用户线程抢资源)。
- 参数:
-XX:+UseConcMarkSweepGC(开启 CMS)。
4. G1 回收器(Garbage-First,JDK 9 默认)
- 原理:替代 CMS,将堆划分为多个大小相等的 Region(区域),兼顾「吞吐量」和「低延迟」。
- 核心特性:
- 混合回收:同时回收新生代和老年代的 Region;
- 可预测停顿:通过
-XX:MaxGCPauseMillis设置目标停顿时间,优先回收垃圾多的 Region; - 无内存碎片:采用「标记 - 整理」算法。
- 适用场景:大内存应用(堆内存 > 4GB),如分布式服务、微服务。
- 参数:
-XX:+UseG1GC(开启 G1)。
5. ZGC/Shenandoah(JDK 11+ 高性能回收器)
- 核心特点:STW 时间控制在毫秒级(甚至微秒级),支持 TB 级内存,适用于超大规模应用(如云计算、大数据)。
- 参数:
- ZGC:
-XX:+UseZGC; - Shenandoah:
-XX:+UseShenandoahGC。
- ZGC:
五、GC 调优核心思路与实践
GC 调优的目标是「减少 Full GC 次数、降低 STW 时间、提升吞吐量 / 响应速度」,核心步骤如下:
1. 基础调优(优先做)
- 设置堆内存大小:
# 初始堆 = 最大堆 = 4GB,避免动态扩展 java -Xms4g -Xmx4g -jar app.jar - 选择合适的回收器:
- 小内存 / 单核心:Serial GC;
- 后台批量任务:Parallel GC;
- Web 服务 / 低延迟:G1 GC;
- 超大内存:ZGC/Shenandoah。
- 禁用显式 GC:
# 禁止 System.gc() 触发 Full GC -XX:+DisableExplicitGC
2. 问题排查(定位 GC 瓶颈)
- 监控 GC 状态:
关键指标:# 实时监控 GC 情况(pid 为进程号) jstat -gc <pid> 1000 # 每 1 秒输出一次YGC/YGCT:Minor GC 次数 / 总耗时;FGC/FGCT:Full GC 次数 / 总耗时;GCT:GC 总耗时。
- 生成 GC 日志:
java -Xms4g -Xmx4g \ -XX:+PrintGCDetails \ -XX:+PrintGCTimeStamps \ -Xloggc:/tmp/gc.log \ -jar app.jar - 分析 GC 日志:使用工具(GCViewer、GCEasy、VisualVM)分析日志,定位频繁 Full GC、STW 过长的原因。
3. 常见问题与解决方案
表格
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| Minor GC 频繁 | 新生代过小 | 增大新生代(调整 -XX:NewRatio 减小比值) |
| Full GC 频繁 | 内存泄漏 / 老年代过小 | 排查内存泄漏(用 MAT 分析堆快照)、增大老年代 |
| STW 时间过长 | CMS/G1 回收器参数不合理 | 调整 -XX:MaxGCPauseMillis、增加 GC 线程数 |
| Metaspace OOM | 动态生成大量类 / 元空间过小 | 增大 -XX:MaxMetaspaceSize、优化类加载逻辑 |
总结
- GC 核心是通过可达性分析判定死亡对象,堆采用分代回收(新生代用复制算法,老年代用标记 - 整理);
- GC 分为 Minor GC(新生代,频繁快)、Major GC(老年代,低频慢)、Full GC(全局,需避免);
- 回收器选择需匹配场景:Parallel 追求吞吐量,G1/CMS 追求低延迟,ZGC 适配超大内存;调优优先保证堆内存足够,再优化回收器参数,最后排查内存泄漏。
更多推荐




所有评论(0)