垃圾回收算法(Garbage Collection)深度解析
核心思想
- 垃圾回收核心目标:
- 定位存活对象 、回收死亡对象
- 可达性分析算法、空间复用优化
生死判定原理
- 可达性分析法(Reachability Analysis)
通过GC Roots(栈变量、静态变量、JNI引用等)构建引用链,未连接的对象视为垃圾
算法评价三维度
指标 | 定义 | 关键影响因素 |
---|---|---|
吞吐量 | 用户代码执行时间占比 | GC频率、单次GC耗时 |
最大暂停时间 | 单次STW最长持续时间 | 内存整理算法选择、堆大小 |
堆使用效率 | 有效内存空间占比 | 算法内存管理机制(碎片化程度) |
黄金三角定律:三者无法同时最优,需根据场景权衡
(缓存系统追求高吞吐、实时系统优先低延迟、嵌入式设备需高内存效率)
经典算法矩阵
1. 标记-清除(Mark-Sweep)
算法流程:
优势:
- 内存利用率100%(不预留空间)
- 无对象迁移开销
缺陷:
- 内存碎片化(外部碎片)
- 双指针遍历内存的低效性
- "致命50%"现象(整体复制性能更好)
2. 复制算法(Copying)
半区复制原理:
// 伪代码示例
void collecting() {for (LiveObject obj : fromSpace) {copyTo(obj, toSpace); // 复制存活对象forwardPtr(obj); // 更新引用指针}swap(fromSpace, toSpace); // 空间角色互换
}
优势:
- 消除内存碎片
- 顺序分配的高效性(指针碰撞)
- 年轻代最佳选择(存活率<10%时高效)
缺陷:
- 内存利用率仅50%
- 不适合大对象场景
3. 标记Credit整理(Mark-Compact)
三步机制:
- 标记存活对象
- 计算对象迁移地址
- 滑动式整理(Sliding Compaction)
优势:
- 100%内存利用率
- 消除碎片问题
缺陷:
- 三次堆遍历的高时间成本
- 老年代整理的默认选择
分代式GC(Generational GC)
设计哲学
弱分代假说:绝大多数对象朝生夕灭
强分代假说:经历多次GC的对象更长寿
内存布局
新生代细节:
- 划分结构:Eden + Survivor*2(8:1:1)
- 回收机制:
- Minor GC触发条件:Eden区满
- 对象晋升阈值:-XX:MaxTenuringThreshold(默认15)
- HotSpot实现:Parallel Scavenge(复制算法)
老年代管理:
- Major GC触发条件:老年代空间不足
- 算法实现:
- CMS(Mark-Sweep)
- G1(局部复制+全局整理)
现代GC技术演进
- 增量式GC:允许GC与用户线程交替执行
- 并发标记:CMS/G1的并发标记阶段
- Region分区:G1/ZGC的内存管理单元
- 颜色指针:ZGC的元数据存储方案
- 读屏障:Shenandoah的并发处理技术
算法性能对比表
算法 | 时间效率 | 空间效率 | 碎片率 | 适用场景 |
---|---|---|---|---|
标记-清除 | 中 | 高 | 高 | 老年代(CMS) |
复制算法 | 高 | 低 | 无 | 新生代 |
标记-整理 | 低 | 高 | 无 | 老年代(Serial) |
分代GC | 极高 | 中 | 混合 | 全堆管理 |
性能调优启示
-
新生代大小设置 → 在STW时间与GC频率间找平衡
-Xmn
参数建议:老年代存活对象总量的1~1.5倍 -
空间分配担保机制:
JDK6之后HandlePromotionFailure
策略优化 -
大对象直接分配老年代:
-XX:PretenureSizeThreshold
参数控制