基于本文回答

播面 播面

文图音视,全方位拆解八股文
0
评论

什么是 Minor GC(Young GC)、Major GC(Old GC)和 Full GC?

知识点图片

在 Java 虚拟机(JVM)的内存管理中,垃圾回收(Garbage Collection, GC)是自动管理内存的核心机制。为了提高回收效率,JVM 通常采用分代收集算法,将堆内存分为新生代(Young Generation)老年代(Old Generation)

基于这种内存划分,GC 也被分为了三种主要类型:Minor GC (Young GC)Major GC (Old GC)Full GC

以下是它们的详细解释和区别:


1. Minor GC(又称 Young GC)

Minor GC 是只针对新生代(Young Generation)进行的垃圾回收。

  • 作用区域:新生代(包括 Eden 区和两个 Survivor 区:S0 和 S1)。
  • 触发条件:当 JVM 无法为新创建的对象在 Eden 区分配内存空间时(即 Eden 区满了),就会触发 Minor GC。
  • 执行过程
    1. 扫描新生代,将 Eden 区和目前正在使用的 Survivor 区中存活的对象,复制到另一个空白的 Survivor 区中。
    2. 如果存活的对象年龄(经历过的 Minor GC 次数)达到了阈值(默认通常是 15),或者 Survivor 区空间不足,这些对象会被晋升(Promote)到老年代。
    3. 清空 Eden 区和原来的 Survivor 区。
  • 特点
    • 非常频繁:因为 Java 中大多数对象都是“朝生夕灭”的(生命周期极短)。
    • 速度极快:新生代空间相对较小,且存活对象少,复制成本低。
    • 会引发 STW (Stop-The-World):所有应用线程都会暂停,但因为回收速度极快,停顿时间通常在毫秒级,用户几乎无感知。

2. Major GC(又称 Old GC)

Major GC 是只针对老年代(Old Generation)进行的垃圾回收。

  • 作用区域:老年代。
  • 触发条件
    • 老年代空间不足时。
    • 在某些垃圾回收器(如 CMS,Concurrent Mark Sweep)中,当老年代内存使用率达到一定阈值(如 92%)时会被触发。
  • 特点
    • 频率较低:老年代存放的都是长生命周期的对象。
    • 速度较慢:老年代空间通常比新生代大,且存活对象多,通常采用“标记-清除”或“标记-整理”算法,比 Minor GC 慢 10 倍以上。
    • 会引发 STW:停顿时间比 Minor GC 长得多。
  • ⚠️ 概念易混淆点:在很多语境中,大家习惯把 Major GC 和 Full GC 混为一谈。但在严格的定义下,Major GC 仅指老年代的回收。不过在实际的垃圾回收器(如 Parallel Scavenge)实现中,老年代满了往往会连带触发一次 Young GC,因此界限有时会比较模糊。

3. Full GC

Full GC 是对整个 JVM 内存空间进行的彻底清理。

  • 作用区域:整个堆内存(新生代 + 老年代)以及 方法区/元空间(Metaspace)
  • 触发条件(情况较多,通常是系统面临内存危机的表现):
    1. 老年代空间不足:新生代对象晋升到老年代时,老年代没有足够的连续空间。
    2. 空间分配担保失败(Promotion Failure):Minor GC 前,JVM 发现老年代的最大可用连续空间小于新生代所有对象总空间,且不允许冒险,或者冒险失败。
    3. 元空间(Metaspace)不足:加载的类信息过多导致方法区爆满。
    4. 显式调用 System.gc():代码中手动建议 JVM 执行 GC(JVM 可能会忽略,但通常会导致 Full GC)。
    5. CMS GC 异常(Concurrent Mode Failure):在使用 CMS 垃圾回收器时,垃圾回收还没执行完,用户的并发线程又产生了大量垃圾塞满老年代。
  • 特点
    • 速度极慢:因为要扫描和清理整个 JVM 内存。
    • 严重的 STW:会导致应用程序出现明显的停顿(卡顿),停顿时间可能长达数秒甚至更久。
    • 性能杀手:JVM 调优的核心目标之一就是尽量减少甚至消除 Full GC

总结与对比表格

特性 Minor GC (Young GC) Major GC (Old GC) Full GC
回收区域 仅新生代 (Eden + Survivor) 仅老年代 整个堆 (新生代+老年代) + 元空间
触发条件 Eden 区空间不足 老年代空间不足/达到阈值 老年代满、元空间满、分配担保失败、System.gc()
发生频率 非常高 较低 极低(应尽量避免)
执行速度 极快(毫秒级) 较慢(比 Minor 慢 10倍+) 极慢(秒级甚至更长)
STW影响 有,但通常微乎其微 有,停顿较明显 有,导致严重的系统卡顿
调优目标 尽量让短命对象在 Minor GC 被回收 减少大对象直接进入老年代 极力避免

💡 给开发者的建议:

  1. 避免创建过大的对象(如极长的数组),因为大对象会直接进入老年代,加速触发 Full GC。
  2. 警惕内存泄漏(如长时间把对象放在静态的 HashMap 中不清理),这会导致老年代被撑满,频繁引发 Full GC 甚至 OOM。
  3. 如果你的系统经常发生长时间卡顿,第一步应该去查看 GC 日志,确认是否正在频繁发生 Full GC。
00:00
00:00