一、分代回收思想
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)收集器
- 工作流程(四个阶段):
-
- 初始标记(STW):标记GC Roots直接关联对象
- 并发标记:追踪引用链,标记所有可达对象
- 重新标记(STW):修正并发标记期间的变动
- 并发清除:清理未标记对象
- 适用场景:交互式应用(网站、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内存管理有所帮助!