shenandoah回收后堆仍保持region分区且无代际边界,空闲region分散存在;存活对象被并发复制至其他region并立即释放原region;转发指针保障引用一致性而不改变布局;连接矩阵替代卡表降低元数据开销。

Shenandoah回收后,堆内存仍保持Region分区结构,但整体不再按代划分,所有Region逻辑上平等,既可存放新对象,也可承载晋升对象。它不设固定年轻代/老年代边界,而是依据对象生命周期和回收价值动态调度Region——这直接决定了回收后内存的“物理连续性”与“逻辑碎片感”并存的特点。
Region分区持续存在,但无代际边界
Shenandoah沿用G1的堆分区模型,将整个堆划分为大小相等(默认2MB)、物理连续的Region。回收完成后,这些Region并未被合并或重排,而是继续以独立单元存在。关键区别在于:它取消了逻辑上的分代设计——没有Eden、Survivor或Old Generation的标签。对象分配不依赖代际策略,而是由分配器根据Region可用空间和回收优先级实时选择。这意味着回收后的空闲Region可能散落在堆中任意位置,不会聚集成大片连续区域。
存活对象被并发复制,旧Region立即可重用
在并发回收阶段(Concurrent Evacuation),Shenandoah将回收集(Collection Set)中所有存活对象复制到其他空闲Region中。复制完成后,原Region即被清空,标记为“可用”,可立即用于后续新对象分配。这种“复制+立即释放”的机制避免了标记-清除带来的碎片累积,也不同于G1需等待整理完成才释放空间。因此,回收后的内存布局表现为:一部分Region完全空闲(刚被清理),一部分含新复制的存活对象,还有一部分正被用户线程写入新对象——三者共存且动态切换。
转发指针维持引用一致性,不改变布局结构
为支持并发复制,每个对象头前插入Brooks Pointer(转发指针)。当对象被复制后,该指针指向新地址;未复制时则指向自身。用户线程通过读屏障自动解析该指针访问正确副本。这一机制完全在对象粒度上运作,不涉及页级或Region级的地址重映射,因此对内存布局本身无扰动——Region的起始地址、大小、状态标识均保持不变,仅内部对象引用关系经重定向后生效。
连接矩阵替代卡表,降低元数据开销
Shenandoah用连接矩阵(Connection Matrix)代替G1的记忆集(Remembered Set)来记录Region间跨区引用。该矩阵是稀疏二维结构,仅记录“Region A → Region B”是否存在引用,不追踪具体字段或对象。它大幅减少元数据内存占用(尤其在大堆场景),但代价是扫描时需遍历整个目标Region而非精确卡页。回收后,连接矩阵会随Region状态更新而动态调整,不影响Region物理布局,只影响GC下次标记时的扫描范围和效率。











