1. RSet(记忆集)在G1垃圾回收器中的核心作用
第一次接触G1垃圾回收器时,我被它Region分区的设计惊艳到了,但真正让我困惑的是每个Region外挂的那个神秘名单——RSet(Remembered Set)。直到有次线上GC日志出现大量"Update RS"耗时异常,才让我下定决心彻底搞懂这个机制。
想象你管理着一栋公寓(堆内存),每个房间(Region)住着不同租客(对象)。突然需要排查哪些房间还有人住(存活对象),传统方法是挨家挨户敲门检查(全堆扫描),而G1的聪明之处在于:它在每个房间门口挂了访客登记簿(RSet),记录着其他房间到本房间的访问关系。当需要清理某个房间时,只需查看登记簿就知道谁还在引用它,无需打扰整栋楼的住户。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. RSet工作原理深度解析
2.1 数据结构本质
RSet本质上是一个哈希映射表,Key是引用来源Region的地址,Value是当前Region内被引用的卡表(Card Table)索引。在G1中,每个Region被划分为512字节大小的卡页,通过卡表位图标记跨Region引用。
实际内存中的存储结构:
- 稀疏引用:使用指针数组存储引用来源Region的地址
- 密集引用:使用位图(Bitmap)标记卡页状态
- 分层设计:根据引用密度自动选择存储方式以节省空间
关键细节:当某个卡页被修改时,写屏障(Write Barrier)会将该卡页标记为"脏卡",并加入全局脏卡队列
2.2 扫描流程详解
以年轻代回收为例的完整扫描过程:
-
并行扫描阶段:
- 每个GC线程领取若干年轻代Region
- 读取各Region的RSet数据结构
- 解析出所有老年代到该Region的引用指针
-
引用处理阶段:
java复制// 伪代码展示RSet扫描核心逻辑 for (Region region : youngRegions) { RememberedSet rset = region.remSet(); for (Reference ref : rset.getReferences()) { Object referent = ref.get();
