Serial Old收集器是什么
serial old是java虚拟机中用于老年代的单线程垃圾回收器,采用标记-整理算法。它主要服务于client模式下的jvm或server模式下发生full gc时的后备方案。该收集器在回收过程中会暂停所有用户线程(stop-the-world),因此不适合对响应时间要求较高的场景。

Serial Old与Parallel Scavenge如何配合工作
Serial Old通常与Serial收集器或Parallel Scavenge收集器搭配使用,构成两种经典的GC组合。当Parallel Scavenge负责年轻代回收并触发老年代GC时,若配置了-XX:+UseAdaptiveSizePolicy,则默认调用Serial Old进行老年代清理。这种组合旨在提供稳定的内存管理,同时保持较低的内存占用。

import java.util.ArrayList;
import java.util.List;
public class SerialOldDemo {
public static void main(String[] args) {
// 设置堆大小,确保触发Full GC
// JVM参数示例: -Xms10m -Xmx10m -XX:+PrintGCDetails -XX:+UseSerialGC
List<byte[]> list = new ArrayList<>();
try {
while (true) {
// 分配大对象,直接晋升到老年代
list.add(new byte[1024 * 1024]); // 1MB
Thread.sleep(100);
}
} catch (OutOfMemoryError e) {
System.out.println("Out of Memory!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}运行上述代码并添加指定JVM参数后,控制台将输出详细的GC日志。由于堆空间极小且不断分配大对象,Young GC无法容纳数据时会触发Full GC。此时Serial Old收集器启动,执行单线程的标记-整理过程,期间应用线程完全停止。最终因内存不足抛出OutOfMemoryError。
立即学习“Java免费学习笔记(深入)”;
Serial Old在CMS收集器失败时的作用
在使用CMS(Concurrent Mark Sweep)收集器时,Serial Old扮演“后备”角色。CMS主打并发低停顿,但其老年代回收基于标记-清除算法,容易产生内存碎片。当CMS未能及时完成回收或遇到老年代空间不足时,JVM会回退到Serial Old进行串行Full GC。这会导致较长的STW时间,但能保证内存的连续性和完整性。

import java.util.concurrent.*;
public class CMSFallbackDemo {
public static void main(String[] args) throws Exception {
// JVM参数示例: -Xms20m -Xmx20m -XX:+UseConcurrentGC -XX:+PrintGCDetails
ExecutorService executor = Executors.newFixedThreadPool(2);
CountDownLatch latch = new CountDownLatch(1);
// 启动一个线程持续分配内存,模拟高负载
executor.submit(() -> {
try {
latch.await();
while (true) {
new byte[1024 * 500]; // 500KB
}
} catch (OutOfMemoryError e) {
System.out.println("OOM in worker");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
// 主线程短暂休眠后释放部分资源,再触发压力
Thread.sleep(500);
latch.countDown();
Thread.sleep(2000);
executor.shutdown();
}
}该程序演示了CMS可能触发的降级行为。在高内存压力下,CMS并发回收可能跟不上分配速度,或者老年代碎片化严重导致无法分配连续空间。此时JVM会强制启动Serial Old进行串行Full GC。虽然这会带来明显的停顿,但它能彻底整理内存,防止因碎片导致的假性OOM。开发者应监控此类回退事件,优化代码减少大对象分配或调整堆大小。


















