1. 垃圾回收算法概述
在软件开发领域,垃圾回收(Garbage Collection, GC)是内存管理的核心机制之一。它自动识别和回收不再使用的内存空间,使开发者从繁琐的手动内存管理中解放出来。不同的垃圾回收算法有着各自的设计哲学和适用场景,理解这些底层原理对于构建高性能应用至关重要。
1.1 标记-清除算法(Mark-Sweep)
标记-清除是最基础的垃圾回收算法,其工作原理分为两个阶段:
- 标记阶段:从根对象(如全局变量、活动线程栈等)出发,遍历所有可达对象并标记为"存活"
- 清除阶段:扫描整个堆内存,回收未被标记的内存块
注意:此算法会产生内存碎片,可能导致后续大对象分配失败。我在实际项目中遇到过因碎片化导致OOM的案例,即使总空闲内存足够。
典型实现案例:
- 早期Java虚拟机(如JDK 1.0)
- CPython的引用计数+标记清除混合机制
1.2 复制算法(Copying)
为解决碎片问题,复制算法将堆空间分为两个等大的半区:
- 只使用其中一个半区(From空间)
- 垃圾回收时,将存活对象复制到另一个半区(To空间)
- 交换两个半区的角色
实测数据表明,这种算法在对象存活率低时效率极高。我在一个消息队列项目中,通过调整新生代空间比例(-XX:SurvivorRatio),使GC时间减少了40%。
1.3 标记-整理算法(Mark-Compact)
结合了前两种算法的优点:
- 标记阶段与标记-清除相同
- 整理阶段将所有存活对象向一端移动
- 清理边界外的内存
这种算法特别适合老年代回收。在某个电商系统的性能调优中,我们将CMS替换为G1(基于标记-整理),使大促期间的STW时间从500ms降至50ms以内。
1.4 分代收集理论(Generational)
现代GC普遍采用的经验法则:
- 新生代:对象朝生夕死,适合复制算法
- 老年代:对象存活时间长,适合标记-整理
- 元空间:存放类元数据,不同虚拟机实现各异
在JVM调优实践中,我通常通过-XX:NewRatio参数调整代际比例,平衡吞吐量与延迟。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 主流垃圾回收器详解
2.1 Serial收集器
单线程工作的经典实现:
- 新生代
