JVM垃圾回收策略详解

一、分代回收思想

1. 分代假说基础
  • 弱分代假说:大多数对象朝生夕死,少数对象长期存活
  • 强分代假说:跨代引用相对于同代引用来说仅占少数
2. 分代内存结构
  • 新生代(Young Generation)
    • 对象首先分配在新生代
    • 存活率低,适合复制算法
    • 包含一个Eden区和两个Survivor区(比例通常为8:1:1)
  • 老年代(Old Generation)
    • 存放长期存活的对象
    • 存活率高,适合标记-整理或标记-清除算法
    • 部分大对象可直接进入老年代(避免复制开销)
3. 对象晋升机制
  • 新对象首先分配在Eden区
  • Minor GC后存活对象复制到Survivor区
  • 经过多次GC仍存活的对象晋升到老年代(默认15次)
  • 动态年龄判定:如Survivor中相同年龄对象总和超过一半空间,年龄大于等于该值的对象直接进入老年代
4. 分代回收的优势
  • 针对不同代的特点采用不同算法,提高回收效率
  • 降低GC范围,减少停顿时间
  • 提高内存利用率,降低碎片产生

二、垃圾判定与回收算法

1. 垃圾判定算法
  • 引用计数法
    • 记录对象被引用次数,为0时回收
    • 无法解决循环引用问题
  • 可达性分析
    • 从GC Roots出发,不可达对象被回收
    • GC Roots包括:
      • 虚拟机栈引用的对象
      • 方法区静态属性引用的对象
      • 方法区常量引用的对象
      • 本地方法栈JNI引用的对象
      • 活跃线程引用的对象
      • 同步锁持有的对象
2. 垃圾回收算法
  • 标记-清除(Mark-Sweep)
    • 标记可回收对象,然后清除
    • 主要缺点:产生大量内存碎片
  • 复制(Copying)
    • 将存活对象复制到另一区域
    • 主要用于新生代,解决碎片问题
  • 标记-整理(Mark-Compact)
    • 标记后将存活对象向一端移动
    • 主要用于老年代,避免内存碎片
  • 分代收集(Generational)
    • 结合上述算法,根据对象生命周期选择合适算法

三、经典垃圾收集器

1. Serial/Serial Old收集器
  • 适用场景:客户端程序,单CPU环境
  • 工作原理:单线程收集,STW(Stop-The-World)
  • 优缺点:简单高效,但停顿时间长
2. ParNew/Parallel/Parallel Old收集器
  • ParNew:Serial的多线程版本,新生代收集器
  • Parallel Scavenge/Parallel Old:注重吞吐量的多线程收集器
  • 优缺点:高吞吐量,但仍有较长STW
3. CMS(Concurrent Mark Sweep)收集器
  • 工作流程(四个阶段):
    1. 初始标记(STW):标记GC Roots直接关联对象
    2. 并发标记:追踪引用链,标记所有可达对象
    3. 重新标记(STW):修正并发标记期间的变动
    4. 并发清除:清理未标记对象
  • 适用场景:交互式应用(网站、GUI应用)
  • 优缺点:低延迟,但产生内存碎片,CPU敏感
4. G1(Garbage First)收集器
  • 内存布局:将堆划分为大小相等的Region,打破传统的连续物理分区
  • 工作机制
    • 保留分代概念,但更灵活地分配Region给不同代
    • 新生代收集(Young GC):收集年轻代Region
    • 混合收集(Mixed GC):收集年轻代和部分老年代Region
    • 采用"停顿预测模型",控制GC停顿时间
  • 优缺点:可预测停顿,但内存占用高,复杂度大

四、ZGC收集器详解

1. ZGC设计理念
  • 以低延迟为首要目标(<10ms)
  • 停顿时间不随堆增大而增长
  • 支持TB级别的超大堆(8MB-16TB)
2. ZGC核心技术
  • 着色指针(Colored Pointers)
    • 利用64位指针的高位存储元数据,标记对象状态
    • 包含三个标记位:Marked0、Marked1(用于标记对象是否存活)和Remapped(用于标记对象是否重映射)
    • 无需额外的记忆集,降低内存使用
  • 读屏障(Load Barrier)
    • 在应用线程读取对象引用时触发
    • 确保线程始终访问对象的最新地址
    • 实现高效的并发转移--基于Remapped标记位
3. ZGC工作流程
  • 并发标记(Concurrent Mark)
    • 从GC Roots出发,标记所有可达对象
    • 利用着色指针记录标记状态
    • 几乎全程并发,应用线程照常运行
  • 并发预备重分配(Concurrent Prepare for Relocate)
    • 选择需要被重分配的Region(垃圾多、内存碎片严重的区域)
    • 创建转发表,记录对象的新地址
  • 并发重分配(Concurrent Relocate)
    • 将存活对象复制到新的Region
    • 通过读屏障,确保应用线程访问的是新地址
  • 并发重映射(Concurrent Remap)
    • 更新所有指向被重分配对象的引用
    • 使用并发算法,减少停顿时间
4. ZGC的分代演进(JDK 21)
  • 背景:JDK 21引入分代ZGC
  • 工作机制
    • 将堆分为年轻代和老年代
    • 年轻代频繁收集(低延迟,适合短命对象)
    • 老年代较少收集(高效处理长寿对象)
  • 优势
    • 降低大约30%的CPU开销
    • 提高吞吐量约10%
    • 大幅降低因分配速率过快导致的"分配停顿"风险
  • 启用方式:通过参数-XX:+UseZGC -XX:+ZGenerational启用
5. ZGC的优缺点
  • 优点
    • 极短的停顿时间(<10ms)
    • 高扩展性(支持TB级堆)
    • 对大型、复杂对象图的高效处理
  • 缺点
    • 吞吐量损失(约15%)
    • 对CPU和内存资源要求较高
    • 仅支持64位平台

五、内存布局的演变

1. 传统分代布局(Serial、ParNew、CMS等)
  • 新生代和老年代是物理上连续的固定区域
  • 新生代比例和大小相对固定
  • Eden和Survivor区比例固定(8:1:1)
  • 对象晋升路径明确且固定
2. Region化布局(G1)
  • 将整个堆划分为大小相等的Region(1MB-32MB)
  • Region动态分配给Eden、Survivor或Old
  • 物理上不连续,但逻辑上仍保留分代概念
  • 新增Humongous区,专门存放大对象
3. 低延迟导向布局(ZGC)
  • 基于不同大小的Region
  • 小型Region(2MB)、中型Region(32MB)和大型Region(N*2MB)
  • JDK 21之前不区分分代,JDK 21后可选分代模式
  • 通过着色指针和读屏障实现并发转移

六、垃圾收集器选择与应用

1. 选择依据
  • 应用类型:批处理、交互式、实时应用
  • 硬件资源:CPU核心数、内存大小
  • 性能目标:吞吐量优先还是低延迟优先
2. 典型应用场景
  • Parallel:批处理、科学计算
  • CMS:传统Web应用、中等交互需求
  • G1:大内存Web应用、企业级应用服务器
  • ZGC:实时交易、游戏、金融分析系统

这份笔记系统地总结了JVM垃圾回收的分代思想、核心算法和主要收集器,特别详细地介绍了ZGC的工作原理和优势,希望对您深入理解JVM内存管理有所帮助!

垃圾回收器的对比

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值