JVM垃圾回收器整理

‌一、基础垃圾回收算法

  1. 标记-清除(Mark-Sweep)
    • 原理‌:
      • 标记阶段‌:从 GC Roots(如静态变量、活动线程栈中的对象等)出发,遍历所有可达对象,标记为存活。
      • 清除阶段‌:遍历堆内存,回收未被标记的对象。
    • 优点‌:实现简单。
    • 缺点‌:内存碎片化;两次遍历(标记和清除)导致效率较低。
    • 应用场景‌:老年代(如 CMS 收集器)。
  2. 标记-整理(Mark-Sweep-Compact)
    • 原理‌:
      • 标记阶段‌:与标记-清除相同,标记存活对象。
      • 整理阶段‌:将存活对象向内存一端移动,清理边界外的内存。
    • 优点‌:无碎片化;内存利用率高。
    • 缺点‌:整理阶段需移动对象,效率较低。
    • 应用场景‌:老年代(如 Parallel Old、G1 收集器)。
  3. 复制(Copying)
    • 原理‌:
      • 将内存分为两块(如 Eden 区和 Survivor 区),每次只使用一块。
      • 存活对象被复制到另一块,原内存块整体回收。
    • 优点‌:无碎片化;适合存活率低的对象。
    • 缺点‌:内存利用率低(需预留一半空间)。
    • 应用场景‌:新生代(如 Serial、ParNew 等收集器)。
  4. 分代收集(Generational Collection)
    • 核心思想‌:根据对象存活周期将堆划分为‌新生代‌(Young Generation)和‌老年代‌(Old Generation)。
      • 新生代‌:对象存活率低,使用‌复制算法‌(如 Eden 区到 Survivor 区)。
      • 老年代‌:对象存活率高,使用‌标记-清除‌或‌标记-整理‌算法。
    • 优化逻辑‌:结合不同算法,平衡效率和内存利用率。

注:   jvm未采用“引用计数法”算法,因为无法解决循环引用问题

‌二、Java 垃圾收集器

Java 虚拟机(JVM)基于上述算法实现了多种垃圾收集器,适用于不同场景:

  1. Serial 收集器
    • 特点‌:单线程,简单高效;全程 STW(Stop-The-World)。
    • 适用场景‌:客户端应用或小内存环境。
  2. Parallel Scavenge 收集器
    • 特点‌:多线程,关注高吞吐量(Throughput)。
    • 适用场景‌:后台计算型应用(如批处理)。
  3. ParNew 收集器
    • 特点‌:Serial 的多线程版本,用于新生代。
    • 适用场景‌:配合 CMS 收集器使用。
  4. CMS(Concurrent Mark-Sweep)收集器
    • 特点‌:并发标记清除,减少 STW 时间;但内存碎片化严重。
    • 阶段‌:
      1. 初始标记(STW): 标记GC Roots直接关联的对象(STW时间极短)
      2. 并发标记: 从GC Roots直接关联对象开始遍历整个引用链的过程(耗时长,不需要停顿用户线程,用户线程与GC线程并发执行)
      3. 重新标记(STW): 使用增量更新避免对象消失问题,修正并发标记期间改动的对象(需要STW,耗时比步骤1长,比步骤2短)  
      4. 并发清除: 清理标记阶段判断已死亡的对象、重置状态等(该阶段也是并发执行)
    • 适用场景‌:对延迟敏感的服务端应用。
  5. G1(Garbage-First)收集器
    • 特点‌:
      • 将堆划分为多个 Region,优先回收价值高的 Region(Garbage-First)。
      • 结合标记-整理和复制算法,可预测停顿时间。
    • 适用场景‌:大内存、低延迟应用(JDK 9+ 默认收集器)。
  6. ZGC 与 Shenandoah
    • 特点‌:
      • 超低延迟(STW 时间控制在 10ms 以内)。
      • 基于并发标记和指针染色技术(如 ZGC 的染色指针)。
    • 适用场景‌:超大堆内存(TB 级)和实时性要求极高的系统。

特殊说明:CMS和G1都是三色标记算法,在并发情况下三色标记会产生多标(浮动垃圾)和漏标问题,多标可以在下一次垃圾回收时再进行回收解决,漏标处理不当可能会造成空指针异常。

漏标产生的条件:一个黑节点指向了白色节点,灰色节点与白色节点断开了引用(二者条件必须同时存在,只要破坏其中一个条件即可解决漏标问题)。

CMS:通过写屏障+增量更新解决,原理是当黑节点B指向白节点E时,将B-->E记录到集合中,在重新标记阶段通过循环集合以B节点为起始节点重新标记。

G1:通过写屏障+SATB(原始快照)解决,原理是当灰色节点C与白色节点E断开引用时,将C-->E记录到集合中,在重新标记阶段通过循环集合以E节点为起始节点进行标记。

为了解决漏标,CMS不得不重新扫描从而造成性能下降,而G1由于从白色节点开始,假如没有活跃节点指向它,这时候就无法回收只能下次回收,可能会造成内存空间的浪费。


‌三、算法与收集器的选择

  1. 吞吐量优先‌:Parallel Scavenge + Parallel Old。
  2. 低延迟优先‌:G1、ZGC 或 Shenandoah。
  3. 内存限制‌:Serial 或 ParNew + CMS。

‌四、GC 优化建议

  1. 避免频繁创建短生命周期对象,减少 Minor GC。
  2. 合理设置堆大小(-Xms, -Xmx)和分代比例(-XX:NewRatio)。
  3. 根据应用特性选择收集器(如 -XX:+UseG1GC)。
  4. 监控 GC 日志(-Xlog:gc*)和分析工具(如 VisualVM、GCEasy)。

五、JDK默认垃圾回收器

1. JDK1.4 及更早版本

  • 默认 GC‌‌Serial GC‌(串行垃圾回收器),新生代和老年代均使用单线程回收

‌2. JDK5 JDK8‌

  • ‌JDK5/JDK6‌
    • 服务端模式新生代默认 ‌Parallel Scavenge‌(并行回收),老年代默认 ‌Serial Old‌(串行回收)。
    • 客户端模式全代使用 ‌Serial GC‌‌。
  • ‌JDK7/JDK8‌
    • 服务端模式默认组合升级为 ‌Parallel Scavenge(新生代) + Parallel Old(老年代)‌,全面支持多线程并行回收以提高吞吐量‌。
    • 客户端模式仍为 ‌Serial GC‌‌。

‌3. JDK9 JDK21(最新版本)

  • 默认 GC‌‌G1(Garbage-First)‌,统一管理新生代和老年代,通过分代 Region 设计平衡吞吐量与低延迟‌。
  • 后续版本优化
    • ‌JDK11+‌支持 ‌ZGC‌(超低停顿时间)和 ‌Shenandoah‌(并发回收),但默认仍为 G1‌。
    • ‌JDK21‌延续 G1 为默认,强化低延迟回收器的稳定性‌。

总结

  • 早期版本(JDK1.4-6:以 ‌Serial GC‌ ‌Parallel Scavenge + Serial Old‌ 为主,侧重简单性和单核性能
  • ‌JDK7-8‌:转向 ‌Parallel Scavenge + Parallel Old‌,优化多核环境下的吞吐量
  • ‌JDK9 及之后‌G1‌ 成为主流默认,兼顾吞吐量与延迟,支持大内存和复杂应用场景

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值