Java中的JVM垃圾回收算法详解
字数 615 2025-11-10 17:00:18
Java中的JVM垃圾回收算法详解
题目描述
垃圾回收算法是JVM自动内存管理的核心,负责识别并回收不再使用的对象。常见的垃圾回收算法包括标记-清除、标记-复制、标记-整理等,每种算法都有其特定的工作原理、优缺点和适用场景。
知识要点
- 标记-清除算法
- 标记-复制算法
- 标记-整理算法
- 分代收集理论
详细讲解
1. 垃圾回收的基本概念
- 目标:自动回收堆内存中不再被引用的对象
- 关键步骤:标记(找出存活对象)→ 回收(清理垃圾对象)
- 评判标准:内存利用率、停顿时间、吞吐量
2. 标记-清除算法
步骤分解:
1. 标记阶段:从GC Roots开始遍历,标记所有可达对象为"存活"
2. 清除阶段:遍历整个堆,回收未被标记的对象内存
示例流程:
初始堆状态:[A(存活), B(垃圾), C(存活), D(垃圾)]
标记阶段:标记A、C为存活状态
清除阶段:回收B、D占用的内存
最终堆状态:[A(存活), C(存活), 空闲, 空闲]
优缺点分析:
优点:实现简单,不需要对象移动
缺点:
- 产生内存碎片(内存不连续)
- 分配效率低(需要遍历空闲链表)
- 执行效率随堆大小增加而下降
3. 标记-复制算法
核心原理:将内存分为大小相等的两块,每次只使用一块
工作流程:
1. 标记阶段:标记存活对象
2. 复制阶段:将存活对象复制到另一块内存
3. 清理阶段:清空当前使用的整块内存
内存布局示例:
内存A:[A(存活), B(垃圾), C(存活)]
内存B:[空闲, 空闲, 空闲]
复制后:
内存A:[全部清空]
内存B:[A(存活), C(存活), 空闲]
优缺点分析:
优点:
- 无内存碎片问题
- 分配高效(指针碰撞分配)
缺点:
- 内存利用率只有50%
- 复制存活对象有开销
适用场景:存活对象较少的年轻代(如Serial、ParNew回收器)
4. 标记-整理算法
执行步骤:
1. 标记阶段:与标记-清除相同,标记所有存活对象
2. 整理阶段:将所有存活对象向内存一端移动
3. 清理阶段:清理边界外的所有内存
内存变化示例:
整理前:[A(存活), B(垃圾), C(存活), D(垃圾)]
整理后:[A(存活), C(存活), 空闲, 空闲]
优缺点分析:
优点:
- 无内存碎片问题
- 内存利用率高
缺点:
- 移动对象需要更新引用
- 停顿时间相对较长
适用场景:存活对象较多的老年代(如CMS的并发失败后备方案)
5. 分代收集理论
理论基础:不同对象的生命周期特征不同
内存划分:
- 年轻代(Young Generation)
- 特点:对象朝生夕死,回收频繁
- 算法:标记-复制算法(如Eden+Survivor模式)
- 回收类型:Minor GC/Young GC
- 老年代(Old Generation)
- 特点:对象存活时间长
- 算法:标记-清除或标记-整理
- 回收类型:Major GC/Old GC
- 元空间(Metaspace)
- 存储类元数据信息
- 回收条件比较苛刻
分代收集流程示例:
1. 新对象分配在Eden区
2. Eden区满时触发Minor GC
3. 存活对象复制到Survivor区
4. 年龄达到阈值的对象晋升到老年代
5. 老年代空间不足时触发Full GC
6. 算法对比与选择
| 算法 | 内存开销 | 时间复杂度 | 空间效率 | 适用场景 |
|---|---|---|---|---|
| 标记-清除 | 低 | 中等 | 碎片化 | CMS老年代 |
| 标记-复制 | 50%浪费 | 存活对象少时低 | 无碎片 | 年轻代 |
| 标记-整理 | 低 | 较高 | 无碎片 | 老年代 |
实际应用
- Parallel Scavenge:年轻代用复制算法,老年代用标记-整理
- CMS:老年代主要用并发标记-清除,碎片多时用标记-整理
- G1:将堆划分为多个Region,综合运用各种算法
- ZGC:采用染色指针和读屏障技术,减少停顿时间