标记-整理算法成为full gc首选,因其能消除老年代内存碎片:老年代对象存活率高、不宜复制,标记-清除虽快但累积碎片导致大对象分配失败,而标记-整理通过紧凑排列存活对象确保连续空间,兼顾回收与可用性。

标记-整理算法成为 Full GC 的首选,核心原因在于它能解决老年代最棘手的问题:内存碎片。老年代对象存活率高、生命周期长,不适合复制;而标记-清除虽快,却会不断累积碎片,最终导致大对象无法分配——哪怕总空间充足。这时,必须靠标记-整理来“压平”内存,确保连续空间可用。
老年代的现实约束决定算法选择
新生代用复制算法,是因为对象“朝生夕死”,存活率通常低于15%,复制成本低、效率高。但老年代不同:存活对象往往超90%,甚至长期驻留(如缓存、单例、静态集合)。复制算法在这里不仅浪费一半空间,还会因频繁移动大量对象而拖慢速度。标记-清除虽不移动对象、停顿短,但放任碎片滋生,迟早触发 Allocation Failure——不是没空间,而是没“连续”空间。标记-整理是唯一能在不额外预留空间的前提下,既回收垃圾又消除碎片的算法。
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
Full GC 的目标不只是回收,更是重建可用性
一次 Full GC 不仅要清理垃圾,更要让系统恢复稳定运行能力。尤其在服务类应用中,下一次请求可能马上到来,必须保证老年代能立刻容纳新晋升的大对象(比如一个 2MB 的订单聚合对象)。标记-整理通过将存活对象紧凑排列,直接提供一块干净、连续的空闲区域,避免后续 Minor GC 晋升时再次失败。这比“先标记-清除,再等下次 GC 时再整理”更可靠——因为下次可能就是 OOM。
主流收集器的实际策略印证该选择
- Serial Old 和 Parallel Old 默认采用标记-整理,本质是为吞吐量优先场景提供确定性内存布局;
- CMS 虽主打并发标记-清除,但一旦出现“并发模式失败”,就会退化为 Serial Old,强制执行标记-整理+Full GC;
- G1 和 ZGC 等新型收集器虽弱化了分代概念,但仍内置类似整理逻辑(如 G1 的 Region 整合、ZGC 的染色指针+重映射),说明“整理”不是过时设计,而是碎片治理的底层刚需。
它慢,但慢得必要
标记-整理确实带来更长 STW:需遍历所有存活对象、计算新地址、批量移动、修正引用。5GB 老年代可能停顿 2~4 秒。可如果不用它,碎片会让系统在数次 Minor GC 后就陷入“明明有空间却不断 Full GC”的死循环。日志里反复出现 [Full GC (Allocation Failure)] 却几乎不释放内存,往往就是标记-清除遗留碎片 + 晋升失败的典型信号。此时,宁可接受一次稍长的停顿,也要换来后续几分钟的稳定。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










