Serial 垃圾回收器是 JVM 最古老、最基础、最简单的垃圾回收器,也是理解其他更复杂回收器的基础。
一、Serial 回收器的定位与设计目标
-
核心特点:单线程 (Single-Threaded)
- 这是 Serial 回收器最根本的特征。无论是进行 垃圾标记 (Marking) 、清除 (Sweeping) 、复制 (Copying) 还是 整理 (Compacting) ,它都只使用一个单独的线程来执行所有垃圾回收工作。
-
工作模式:Stop-The-World (STW)
- 在进行垃圾回收时,它必须暂停所有应用线程 (Application Threads)。这意味着在 GC 期间,整个 Java 应用是完全停止响应的。
-
设计目标:简单性与客户端/低资源环境
-
简单性: 算法实现简单直接,代码量小,易于理解和维护。它是其他复杂回收器的基础。
-
低内存/CPU 开销: 单线程工作意味着它自身消耗的内存(元数据)和 CPU 资源非常少。
-
客户端模式 (Client Mode) 默认: 在 JDK 8 及之前的版本中,对于运行在 客户端模式 (Client Mode) 下的 JVM(通常指桌面 GUI 应用或小型应用),Serial 回收器是年轻代的默认回收器(老年代默认搭配 Serial Old)。这是因为桌面应用通常对短暂的停顿不那么敏感,且更看重 JVM 启动速度和资源占用。
-
-
适用场景:
-
运行在资源极其受限的环境(如嵌入式设备、微控制器)。
-
单核 CPU 环境(多线程 GC 在此类环境没有优势)。
-
小型堆内存(几十 MB 到一两百 MB)。
-
对短暂停顿不敏感的应用(如简单的命令行工具、后台守护进程)。
-
作为学习 JVM GC 原理的基础模型。
-
二、核心组件与算法
Serial 回收器通常指代两个具体的回收器实现,分别管理不同的代:
-
年轻代:Serial 回收器 (Serial Collector)
-
算法:复制算法 (Copying Algorithm)
-
堆结构: 年轻代划分为一个较大的
Eden
区和两个较小的Survivor
区 (From
,To
)。默认比例Eden : Survivor = 8:1
。 -
回收过程 (STW):
-
触发条件: Eden 区空间不足以分配新对象。
-
STW: 暂停所有应用线程。
-
标记: 单 GC 线程从 GC Roots (栈引用、静态变量、JNI 引用等)开始,标记 Eden 区和当前
From
Survivor 区中的存活对象。 -
复制: 单 GC 线程将标记出的存活对象复制 到
To
Survivor 区。-
新对象直接在 Eden 区分配。
-
对象在 Survivor 区之间每熬过一次 GC,年龄增加 1。
-
达到晋升年龄阈值 (
-XX:MaxTenuringThreshold
) 的对象会被晋升 (Promote) 到老年代。 -
如果
To
Survivor 区空间不足以容纳所有存活对象,或者存活对象年龄过大,会直接晋升到老年代。
-
-
清空与交换: 单 GC 线程清空 Eden 区和刚使用完的
From
Survivor 区。交换From
和To
的角色(下次 GC 时,当前的To
变成新的From
)。
-
-
特点: 算法简单高效,无内存碎片。STW 时间与存活对象数量成正比。对于小型堆和存活对象少的应用,停顿时间可以很短(几十毫秒)。
-
-
老年代:Serial Old 回收器 (Serial Old Collector)
-
算法:标记-整理算法 (Mark-Sweep-Compact Algorithm)
-
回收过程 (STW):
-
触发条件:
-
显式调用
System.gc()
。 -
老年代空间不足(年轻代对象晋升失败,或大对象直接分配失败)。
-
元空间 (Metaspace) / 永久代 (PermGen) 空间不足。
-
在某些情况下,作为 CMS 或 G1 回收失败时的后备方案 (
Promotion Failed
或Concurrent Mode Failure
时触发的 Full GC)。
-
-
STW: 暂停所有应用线程。
-
标记: 单 GC 线程从 GC Roots 出发,递归遍历整个老年代对象图,标记所有存活对象。
-
整理 (滑动压缩):
-
计算位置: 单 GC 线程计算每个存活对象在整理后应该移动到的目标地址(通常是堆内存空间的起始端开始紧密排列)。
-
更新引用: 单 GC 线程更新所有指向被移动对象的引用(指针),确保应用恢复后能找到正确的新位置。这一步需要遍历整个对象图,非常耗时。
-
移动对象: 单 GC 线程将存活对象复制(移动)到计算好的新地址。
-
-
清除: 单 GC 线程回收掉整理后边界以外的所有空间(即死亡对象占用的空间)。
-
-
特点:
-
解决内存碎片: 整理后得到连续的大块空闲空间,消除了内存碎片。
-
STW 时间长: 整个标记-整理-更新引用过程由单线程 完成,对于大堆 或存活对象多 的老年代,停顿时间会非常长(几秒甚至几十秒),对应用响应性影响巨大。
-
可靠性高: 作为最简单、最"笨重"的回收器,它通常是其他回收器失败时的最后保障。
-
-
三、核心特性与优劣势
-
优势:
-
极低的内存开销: 自身数据结构简单,几乎不占用额外的堆内存(不像 G1 需要 RSet,CMS 需要卡表等)。
-
极低的 CPU 开销 (GC 线程本身): 仅使用一个 GC 线程,在非 GC 期间没有额外线程消耗 CPU。
-
算法简单可靠: 实现简单,逻辑清晰,是学习 GC 原理的绝佳起点。作为后备方案非常稳定。
-
无内存碎片 (Serial Old 整理后): 老年代回收后空间连续。
-
适合微型/嵌入式环境: 在资源极其受限(内存小、CPU 单核)的场景下是唯一或最佳选择。
-
-
劣势:
-
长时间的 STW 停顿: 这是最大的缺点!单线程 处理整个堆(尤其是老年代)的垃圾回收工作,导致 GC 停顿时间与堆大小、存活对象数量成正比。对于现代动辄几 GB 甚至更大的堆,Serial Old 的 Full GC 停顿时间完全不可接受。
-
完全暂停应用: 在 GC 期间,应用完全停止服务,无法响应任何请求。这对需要交互性或低延迟的应用(Web 服务、GUI 应用)是致命的。
-
无法利用多核优势: 在现代多核 CPU 成为标配的情况下,Serial 回收器无法并行化利用多个核心来加速 GC 过程,造成了巨大的硬件资源浪费。
-
吞吐量相对较低: 虽然 GC 自身开销小,但长时间的 STW 直接减少了应用运行的时间,整体吞吐量通常低于 Parallel 或 G1 等多线程回收器(在堆较大时尤其明显)。
-
四、关键配置参数
-
启用 Serial 回收器 (JDK 8 及之前 Client 模式默认):
-
年轻代:
-XX:+UseSerialGC
(显式指定) -
老年代: Serial Old 会自动搭配启用。
-
-
JDK 9+ 的变化:
-
客户端/服务器模式区分逐渐淡化。G1 成为所有平台的默认回收器。
-
但 Serial 和 Serial Old 仍然存在,可通过
-XX:+UseSerialGC
显式启用。
-
-
其他相关参数 (通常使用默认值即可):
-
-XX:SurvivorRatio
: Eden 与 Survivor 区的比例 (默认 8)。 -
-XX:MaxTenuringThreshold
: 对象晋升老年代的最大年龄 (默认 15)。 -
-Xmn
: 设置年轻代大小 (覆盖-XX:NewRatio
)。 -
-XX:NewRatio
: 老年代与年轻代的比例 (默认在 Client 模式下为 2,即 老年代:年轻代=2:1)。
-
五、使用场景总结
-
历史/默认场景: JDK 8 及之前客户端模式 (Client Mode) 下年轻代的默认回收器。
-
资源极端受限环境: 嵌入式系统、IoT 设备、功能手机等内存 (RAM) 极小 (几十MB) 且 CPU 为单核的环境。
-
简单/非交互式应用: 命令行工具、一次性批处理脚本、后台守护进程等对短暂停顿完全不敏感的小型应用。
-
后备方案: 当其他更先进的回收器 (如 CMS, G1) 发生失败 (Concurrent Mode Failure, Promotion Failed) 时,JVM 会退化使用 Serial Old 进行兜底的 Full GC。
六、与其它回收器的对比
特性 | Serial (Young) / Serial Old (Old) | Parallel Scavenge (Young) / Parallel Old (Old) | CMS (Old) | G1 |
---|---|---|---|---|
线程模型 | 单线程 | 多线程 (并行) | 多线程 (并发 + 并行) | 多线程 (并行 + 并发) |
STW | 完全 STW | 完全 STW | 部分 STW (初始标记、重新标记) | 部分 STW (Young GC, Mixed GC 阶段) |
目标 | 简单、低开销、小堆、Client 模式 | 高吞吐量 | 低延迟 (老年代) | 可预测低停顿、高吞吐、大堆 |
算法 | 复制 (Young) / 标记-整理 (Old) | 复制 (Young) / 标记-整理 (Old) | 标记-清除 (Old) | 复制 (Region 间) |
碎片 | 无 (Old 整理后) | 无 (Old 整理后) | 有 (需 Full GC 整理) | 无 |
适用堆 | 极小堆 (MB 级) | 中小型 -> 大型堆 | 中小型堆 (GB 级) | 大堆 (GB -> TB 级) |
适用场景 | 嵌入式、Client 应用、后备 | 后台计算、批处理 | Web 服务 (历史方案) | 主流服务器应用 (现代默认) |
JDK 默认 | Client Mode (<=JDK8) | Server Mode (<=JDK8) | 无 | >= JDK9 |
CPU 利用 | 低 (单核) | 高 (并行) | 中高 (并发+并行,争抢 CPU) | 高 (并行+并发) |
七、总结
Serial 垃圾回收器是 JVM GC 的基石和起点。它的核心价值在于:
-
极致的简单性: 单线程 STW 模型,算法清晰易懂。
-
最小的资源开销: 内存和 CPU 占用极低。
-
微/嵌入式场景的适用性: 在资源受限环境中不可或缺。
-
可靠的后备: 作为其他先进回收器失败时的安全网。
然而,其单线程 和完全 STW 的本质,使得它在面对现代多核处理器和大内存堆的应用需求时,停顿时间过长 的缺点暴露无遗,完全不适合需要低延迟或高吞吐的服务器端应用。