minor gc由eden区空间不足触发,仅清理eden和一个survivor区;major gc非标准术语,通常指单独回收老年代;full gc则整堆+元空间回收,stw时间最长。

Java堆内存分代模型下的GC触发,核心在于“空间压力驱动”,不是定时发生,而是由各代内存使用达到阈值时主动触发。理解关键在于区分三类回收行为:Minor GC、Major GC 和 Full GC,它们各自对应不同区域、不同条件、不同代价。
Minor GC(新生代GC)怎么被触发
Minor GC 是最频繁的回收动作,只作用于新生代(Eden + 一个 Survivor 区),它的触发条件非常明确:
- Eden 区空间不足:新对象分配时发现 Eden 没有足够连续空间,立即触发 Minor GC;Survivor 区满不会单独触发 GC。
- 每次 Minor GC 会把 Eden 和 From Survivor 中存活的对象复制到 To Survivor;年龄+1,达默认阈值 15(可调 -XX:MaxTenuringThreshold)就晋升老年代。
- 复制过程中若 To Survivor 空间不够容纳所有存活对象,剩余对象直接“担保分配”进老年代。
Major GC(老年代GC)何时发生
Major GC 专指仅清理老年代的回收,实际在 HotSpot 中支持该行为的收集器极少(如 CMS),多数场景下它常被误用为 Full GC 的同义词。真正独立触发 Major GC 的情况包括:
- 老年代空间不足:Minor GC 后对象晋升失败(老年代剩余空间小于晋升对象大小),或大对象(> -XX:PretenureSizeThreshold)直接分配失败。
- CMS 收集器运行中出现 Concurrent Mode Failure,即并发标记未完成但老年代已耗尽,被迫退化为 Serial Old 单线程回收老年代。
- 某些收集器策略允许显式触发(如 Parallel Old 在特定配置下可跳过 Minor GC 直接回收老年代)。
Full GC(整堆回收)的典型诱因
Full GC 开销最大,会暂停全部应用线程(STW 时间远长于 Minor GC),应尽量避免。常见触发路径有:
- 调用 System.gc()(仅建议,不保证执行;加 -XX:+DisableExplicitGC 可禁用)。
- 老年代空间不足,且经过 Minor GC 后仍无法腾出足够空间容纳晋升对象。
- 元空间(Metaspace)内存不足(JDK 8+),加载大量类或动态代理导致元空间扩容失败。
- Minor GC 时,晋升平均大小 > 老年代可用空间,JVM 预判后续会失败,提前触发 Full GC。
- 从 Eden 或 From Survivor 向 To Survivor 复制对象时,单个对象大于 To Survivor 剩余空间,又无法晋升老年代(因老年代也快满),则触发 Full GC。
跨代引用与回收范围的实际影响
虽然 Minor GC 理论上只清理新生代,但为解决“老年代对象引用新生代对象”这类跨代引用问题,多数收集器(如 Parallel、G1)会在 Minor GC 时顺便扫描部分老年代根(如 card table 标记的脏卡),形成事实上的“部分老年代参与”。而所谓 Major GC 是否伴随 Minor GC,取决于收集器实现——CMS 通常不带,Parallel Scavenge 则可能组合触发。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











