g1收集器通过region实现物理扁平化分代:每个region(1mb~32mb)可动态承担eden、survivor、old或humongous角色;rset解决跨region引用;大对象走humongous路径;年轻代大小根据停顿目标动态伸缩。

G1 收集器通过将堆内存划分为多个大小相等、物理上不连续的 Region,彻底解耦了“代”与“物理位置”的绑定关系。传统收集器(如 Parallel、CMS)要求新生代和老年代各自占据一块连续内存区域,而 G1 不再预设某段地址空间专属于某一代——每个 Region 在运行时可动态承担 Eden、Survivor、Old 或 Humongous 角色,逻辑分代依然存在,但物理布局完全扁平化。
Region 是独立单元,不是固定分区
每个 Region 大小在 1MB~32MB 之间(默认由堆总大小 ÷ 2048 推导),彼此独立管理。JVM 不按地址高低硬性划分年轻代/老年代,而是把一批 Region 临时归为“当前新生代集合”,另一批归为“老年代集合”。当一次 Young GC 完成后,原 Eden Region 被清空并重新加入空闲列表;其中存活对象复制到的 Survivor Region,下次可能又变成 Old Region——角色切换完全由回收行为驱动,无需移动内存块。
跨 Region 引用靠 Remembered Set(RSet)维护
物理分散带来一个关键问题:如何高效识别跨代引用?G1 为每个 Region 配备独立的 RSet,记录“哪些其他 Region 中的对象引用了本 Region 的对象”。这样,在回收某个 Region 时,无需扫描整个老年代或新生代,只需查它的 RSet 就能定位外部根引用。RSet 的增量更新由写屏障(Write Barrier)在对象赋值时触发,保证了并发标记阶段的准确性,也使分代边界真正变成逻辑视图而非物理约束。
大对象走 Humongous 路径,绕过常规分代流程
当对象大小超过单个 Region 容量的 50%(例如 Region 为 2MB,则 ≥1MB 即为大对象),G1 会为其分配连续的 Humongous Region。这类 Region 不参与 Eden/Survivor 的复制流程,也不直接进入老年代 Region 池,而是单独管理、延迟回收。这既避免了大对象搅乱年轻代复制效率,也防止其过早挤占老年代空间,实质上是用一种“代外通道”进一步削弱了传统分代模型的刚性。
年轻代大小动态伸缩,不再静态配置
传统收集器需手动设定 -Xmn,固定新生代容量;G1 则通过 -XX:G1NewSizePercent(默认5%)和 -XX:G1MaxNewSizePercent(默认60%)划定弹性区间。JVM 根据 GC 停顿目标(-XX:MaxGCPauseMillis)和实际回收效果,实时增减年轻代占用的 Region 数量。比如压力升高时自动扩大 Eden 区域,降低 Minor GC 频率;停顿超标时则收缩,缩短单次回收时间。这种弹性机制,正是建立在 Region 可自由调配的基础之上。










