在 JVM 的垃圾回收器家族中,串行回收器(Serial GC) 是最古老、最基础的一位成员。虽然它不像 G1、ZGC 那样“高大上”,但正是它奠定了现代垃圾回收的基石。理解 Serial GC,不仅有助于我们应对老系统的性能问题,更能帮助我们深刻理解 GC 的设计思想。
本文将带你从工作原理、回收算法、日志解读、参数配置到应用场景,全方位剖析 Serial GC。
一、什么是串行回收器?
串行回收器是 JDK 中最基本的垃圾回收器之一,它的核心特点可以用两个词概括:单线程 和 独占式。
1.1 单线程回收
串行回收器在进行垃圾回收时,仅使用一个线程来完成所有 GC 工作。这意味着:
-
没有多线程协作的复杂逻辑
-
没有线程切换的开销
-
实现简单,执行高效
1.2 独占式回收(Stop-The-World)

串行回收器是独占式的——当它开始工作时,Java 应用程序中的所有用户线程都必须完全暂停,等待 GC 完成。这个过程被称为 "Stop-The-World"(简称 STW)。
在 GC 期间,所有业务线程都被“冻结”,这对实时性要求较高的系统来说,可能是不可接受的。但在某些场景下,这种“简单粗暴”的方式反而带来了最佳性能。
二、新生代串行回收器(Serial Young GC)
2.1 算法:复制算法
新生代串行回收器采用 复制算法(Copying Algorithm)。
其核心思想是:将新生代内存划分为一个较大的 Eden 区 和两个较小的 Survivor 区(From 和 To)。每次 GC 时,将 Eden 和 From 中存活的对象复制到 To 区,然后清空 Eden 和 From,最后交换 From 和 To 的角色。
为什么用复制算法?
-
新生代对象朝生夕死,存活率极低
-
复制算法的效率与存活对象数量成正比,非常适合新生代
-
实现简单,没有内存碎片问题
2.2 优势与局限
| 实现简单,逻辑高效 | 单线程无法利用多核 CPU |
| 无线程切换开销 | GC 期间必须 STW |
| 在单 CPU 环境下性能优异 | 堆内存较大时停顿时间过长 |
2.3 参数配置
-XX:+UseSerialGC
使用该参数后,JVM 会同时启用:
-
新生代:Serial 收集器(使用复制算法)
-
老年代:Serial Old 收集器(使用标记-压缩算法)
在 Client 模式 下,Serial GC 是 JVM 的默认垃圾收集器。
三、老年代串行回收器(Serial Old GC)
3.1 算法:标记-压缩算法
老年代串行回收器采用 标记-压缩算法(Mark-Compact Algorithm)。
该算法分为三个阶段:
标记(Mark):从 GC Roots 出发,标记所有存活对象
压缩(Compact):将所有存活对象向一端移动,使它们连续排列
清理(Sweep):清理掉边界以外的内存空间
为什么老年代不用复制算法?
-
老年代对象存活率高,复制成本太高
-
标记-压缩算法避免了内存碎片,且不需要额外空间
3.2 注意:老年代 GC 停顿更长
由于老年代空间通常更大,且存活对象更多,Full GC 的停顿时间往往远超 Young GC。在堆内存较大的应用中,一次 Serial Old GC 可能导致秒级甚至更长的停顿,这在生产环境中需要特别警惕。
3.3 参数配置
# 方式一:新生代和老年代都使用串行
-XX:+UseSerialGC
# 方式二:新生代使用 ParNew,老年代使用串行
-XX:+UseParNewGC
# 方式三:新生代使用 ParallelGC,老年代使用串行
-XX:+UseParallelGC
四、GC 日志深度解读
4.1 新生代 GC 日志
[GC [DefNew: 310K->194K(2368K), 0.0269163 secs] 310K->194K(7680K), 0.0269513 secs] [Times: user=0.00 sys=0.00, real=0.03 secs]
我们来逐段拆解:
| GC | 表示这是一次 Young GC(而非 Full GC) |
| [DefNew | 表示 GC 发生在新生代(Default New Generation),这是 Serial GC 特有的名称 |
| 310K->194K(2368K) | 新生代:GC前已使用→GC后已使用(该区域总容量) |
| 310K->194K(7680K) | 整个堆:GC前已使用→GC后已使用(堆总容量) |
| 0.0269163 secs | 该区域 GC 耗时 |
| [Times: user=0.00 sys=0.00 real=0.03 secs] | 见下方详解 |
Times 字段详解:
-
user:GC 线程消耗的 CPU 时间
-
sys:操作系统调用及等待系统事件的时间
-
real:应用程序实际暂停的时间(挂钟时间)
对于 Serial GC,由于只使用单线程,real ≈ user + sys。
4.2 老年代 GC(Full GC)日志
25.299: [Full GC (Allocation Failure) 25.300: [Tenured: 126975K->84388K(126976K), 0.1865275 secs] 741375K->84388K(741376K), [Metaspace: 3476K->3476K(1056768K)], 0.1866490 secs] [Times: user=0.19 sys=0.00, real=0.18 secs]
| Full GC | 表示这是一次 Full GC |
| (Allocation Failure) | GC 触发原因:分配对象失败(内存不足) |
| [Tenured | 老年代(Tenured Generation)的 GC 信息 |
| 126975K->84388K(126976K) | 老年代:GC前→GC后(总容量) |
| 741375K->84388K(741376K) | 整个堆:GC前→GC后(总容量) |
| Metaspace: 3476K->3476K(1056768K) | 元空间信息(JDK 8+) |
4.3 不同收集器的新生代名称对照
| Serial | [DefNew | Default New Generation |
| ParNew | [ParNew | Parallel New Generation |
| Parallel Scavenge | [PSYoungGen | Parallel Scavenge Young Generation |
五、示例代码与运行验证
下面我们用一段代码来模拟内存溢出,观察 Serial GC 的工作过程:
import java.util.Random;
public class GCDemo {
public static void main(String[] args) {
System.out.println("===== GCDemo, Hello =====");
try {
String str = "GCDemo";
while (true) {
str += str + new Random().nextInt(77777777)
+ new Random().nextInt(88888888);
str.intern();
}
} catch (Throwable e) {
e.printStackTrace();
}
}
}
运行参数:
-XX:+UseSerialGC -Xms10m -Xmx10m -XX:+PrintGCDetails
输出日志示例:
[GC [DefNew: 1393K->25K(3072K), 0.009758 secs] 5793K->5793K(9920K), 0.0010059 secs]
[Full GC (Allocation Failure) [Tenured: 5767K->4167K(6948K), 0.0023995 secs] …
java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:3332)
at java.lang.AbstractStringBuilder.ensureCapacityInternal(…)
可以看到:
DefNew 确认了 Serial GC 在新生代工作
Tenured 确认了 Serial Old 在老年代工作
频繁的 GC 最终导致 OutOfMemoryError
六、总结:Serial GC 的优缺点与应用场景
6.1 优点
✅ 实现简单,逻辑高效 — 代码成熟稳定,几乎没有复杂 bug
✅ 单线程无交互开销 — 没有多线程锁竞争和上下文切换
✅ 在单 CPU 环境下性能最佳 — 多线程反而会带来额外开销
✅ 内存占用小 — 不需要维护复杂的数据结构
6.2 缺点
❌ STW 停顿时间长 — 堆内存越大,停顿越明显
❌ 无法利用多核 CPU — 在多核时代显得有些“落伍”
❌ 用户体验差 — 在交互式应用中,停顿可能导致卡顿
6.3 适用场景
| Client 模式下的 JVM | ✅ 默认选择 | 资源受限环境,简单高效 |
| 单 CPU 服务器 | ✅ 最佳选择 | 多线程无法带来收益 |
| 堆内存 < 100MB | ✅ 可接受 | 停顿时间可控 |
| 实时 Web 应用 | ❌ 不推荐 | 停顿影响用户体验 |
| 大堆内存(>4GB) | ❌ 不推荐 | 停顿时间过长 |
网硕互联帮助中心




评论前必须登录!
注册