本文共 1687 字,大约阅读时间需要 5 分钟。
分代收集理论
分代收集理论是Java垃圾回收机制中的核心理论之一,主要描述对象在不同代中的存活特性及其对垃圾回收策略的影响。
弱分代假说(Weak Generational Hypothesis)
绝大多数对象的生命周期较短,都是朝生夕灭的。强分代假说则与之形成对比,认为熬过越多次垃圾收集过程的对象越难消亡。
强分代假说(Strong Generational Hypothesis)
对象的分代能力直接影响其存活概率。
跨代引用假说(Intergenerational Reference Hypothesis)
跨代引用关系相对同代引用占比极低。
跨代引用假说的解决方案包括建立记忆集(Referenced Set),将老年代划分为若干小块,标识跨代引用存在的老年代内存区域。Minor GC时,只有包含跨代引用的内存块被加入GC Roots扫描范围。
各类收集方式
垃圾回收适用于非实时内存管理体系,主要收集方式有以下几种:
新生代收集(Minor GC/Young GC)
目标新生代的垃圾回收,适用于新生代占总堆内存的大多比例的情况。
老年代收集(Major GC/Old GC)
收集老年代的垃圾,仅有部分收集器支持。
混合收集(Mixed GC)
收集新生代全部与部分老年代,主要由G1收集器完成。
整堆收集(Full GC)
收集新生代、老年代及方法区,全盘清扫,适用于内存分配缓慢的情况。
标记-清除算法
标记-清除是垃圾回收的基础算法,主要程序逻辑为:
标记阶段:遍历堆对象,标记不可回收对象; 清除阶段:收集标记对象内存,释放回收空间。 其缺点主要表现在:
- 效率低下:大量可回收对象时,标记和清除耗时较长;
- 空间碎片化:标记清除后堆内存分散,可能导致内存碎片。
标记-复制算法
针对标记-清除的效率问题,引入复制算法:
- 分区方式:将堆分为两半,使用一半存活对象,另一半待定期清理;
- 复制与清理:存活对象复制至另一区域后,清理已使用区域。
该算法优点:
- 实现较简单,执行效率高;
- 内存占用减半(新生代常用)。
HotSpot虚拟机将新生代划分为Eden(起始空间)和两块Survivor空间。垃圾回收时,将Eden和使用过的Survivor复制至另一Survivor空间,清理已用区域。
标记-整理算法
针对对象存活率高的问题,采用标记-整理算法:
标记阶段:同标记-清除; 整理阶段:将存活对象移动至一侧,清理边界外的内存。 优点:
- 内存利用率高(无空间浪费);缺点:
- 对大规模存活对象的移动要求高udge,不易处理。
整理算法的另一特点:
- 不会导致大量Stop The World停顿,适合吞吐量优先的环境。
根节点枚举
根节点枚举是垃圾收集的起点,确保回收对象的强一致性。
- GC Roots:
- 全局引用(常量、静态字段);
- 执行上下文(栈、本地方法变量)。
实现方式:
- 使用OopMap数据结构记录执行上下文中的堆指针;
- GC过程中快速扫描OopMap即可完成根节点枚举。
安全点
为规避Root枚举对用户线程的干扰,引入安全点概念:
- 安全点定义:指令序列具有长时间执行潜力,通常与方法调用、循环、异常处理相关。
- 垃圾收集中断:
- 抢先式中断:强制中断用户线程(不主动等待安全点)。
- 主动式中断:用户线程轮询中断标志,自行挂起至安全点。
安全区域
安全区域用于处理线程不响应GC的情况(如阻塞、睡眠)。
- 线程行为:
- 条件地标识进入安全区域;
- 离开安全区域前检查GC是否完成,待可用;
- 机制便于避免因线程状态不确定而导致的垃圾回收异常。
记忆集与卡表
解决跨代引用问题,记忆集记录老年代与新生代之间的引用关系,采用卡表实现:
- 卡页大小:通常为512字节,记录跨代引用情况。
- 卡表维护:
- 在引用对象赋值时,修改卡表状态;
- UseCondCardMark选项可控制卡表更新优化。
写屏障
维护卡表状态的核心技术,依附于进程分析(解释执行)或即时编译后的机器码执行。写屏障分为:
- 预写屏障(赋值前):设置状态标记;
- 后写屏障(赋值后):清理状态或更新卡表。
转载地址:http://tqtyk.baihongyu.com/