Bohr-L Bohr-L
首页
技术
常见面试题
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

刘博

I'm a slow walker, But I never walk backwards.
首页
技术
常见面试题
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 数据处理与存储类

  • Spring 生态类

  • 缓存问题类

  • 多线程类

  • JVM 类

    • JVM 中一次完整的 GC 流程(从 ygc 到 fgc)是怎样的
      • 如何判断对象可以被回收
      • 你知道哪些垃圾收集算法
      • 虚拟机为什么使用元空间替换了永久代
      • 简述 CMS 垃圾收集器的工作流程,它有什么优缺点?
      • 简述一下 JVM 的内存模型
      • 说说堆和栈的区别
      • 简述 Java 的对象结构
      • JVM 中的即时编译器(JIT)如何工作?
      • 什么是内存屏障?JVM 如何使用内存屏障保证指令执行顺序?
      • 如何排查和解决 JVM 内存泄漏问题?有哪些常用的工具和方法?
      • JVM 如何处理异常?try-catch-finally 结构在字节码层面是如何实现的?
    • MySQL 类

    • Java 8 + 特性类

    • 其他技术类

    • 常见面试题
    • JVM 类
    刘博
    2025-12-28
    目录

    JVM 中一次完整的 GC 流程(从 ygc 到 fgc)是怎样的

    JVM 的 GC(垃圾回收)流程围绕 “分代回收” 展开(基于 “大部分对象朝生夕死” 的假设),将堆内存分为新生代(Young Generation)和老年代(Old Generation),不同代采用不同 GC 算法,完整流程如下:

    # 1. 内存区域划分(分代模型)

    • 新生代:分为 Eden 区(80%)和两个 Survivor 区(From Survivor、To Survivor,各 10%),存储新创建的对象,GC 频率高(Minor GC/YGC);
    • 老年代:存储从新生代晋升的长期存活对象,GC 频率低(Major GC/FGC);
    • 元空间(Metaspace,JDK 8+):存储类元信息(类结构、方法信息),不存储对象,元空间满时会触发 GC,但不影响堆内存的 YGC/FGC。

    # 2. 完整 GC 流程(从对象创建到 FGC)

    # (1)对象创建与 Eden 区分配
    • 新对象优先分配到新生代的 Eden 区(若对象过大,直接分配到老年代,如超过-XX:PretenureSizeThreshold阈值);
    • 当 Eden 区满时,触发Minor GC(YGC)。
    # (2)Minor GC(YGC):回收新生代
    • 步骤 1:标记存活对象:用 “可达性分析”(从 GC Roots 出发,如线程栈引用、静态变量引用)标记 Eden 区和 From Survivor 区的存活对象;
    • 步骤 2:复制存活对象:将 Eden 区和 From Survivor 区的存活对象复制到 To Survivor 区,同时将对象的 “年龄计数器”+1(每经历一次 YGC,年龄 + 1);
    • 步骤 3:清空死亡对象:清空 Eden 区和 From Survivor 区的死亡对象(无需标记清除,直接清空,效率高);
    • 步骤 4:交换 Survivor 区:将 From Survivor 和 To Survivor 的角色互换(From 变 To,To 变 From),确保下次 YGC 时 To Survivor 是空的;
    • 步骤 5:对象晋升老年代:若存活对象的年龄达到-XX:MaxTenuringThreshold(默认 15),或 To Survivor 区空间不足(存活对象超过 To Survivor 容量的 50%),将对象晋升到老年代。
    # (3)老年代满触发 Major GC/FGC
    • 随着 YGC 的频繁执行,老年代的对象逐渐增多;当老年代空间满时(或老年代剩余空间不足以容纳新生代晋升的对象),触发Major GC(仅回收老年代) 或Full GC(回收新生代 + 老年代 + 元空间);
    • 注意:不同 GC 收集器对 FGC 的定义不同,如 CMS 收集器的 FGC 是回收老年代,而 G1 收集器的 FGC 是全局回收;通常我们说的 FGC 指 “全局垃圾回收”,会暂停所有用户线程(STW,Stop The World),影响应用性能。
    # (4)Full GC(FGC)流程(以 CMS 收集器为例)

    CMS(Concurrent Mark Sweep)是老年代收集器,采用 “标记 - 清除” 算法,FGC 流程分为 4 步,其中 2 步并发执行,减少 STW 时间:

    1. 初始标记(Initial Mark,STW):快速标记 GC Roots 直接引用的老年代对象,STW 时间短(毫秒级);
    2. 并发标记(Concurrent Mark,非 STW):从初始标记的对象出发,遍历老年代的对象引用链,标记所有存活对象,与用户线程并发执行,无 STW;
    3. 重新标记(Remark,STW):修正并发标记期间因用户线程操作导致的标记变动(如对象新增、引用断开),STW 时间比初始标记长,但比 Serial Old 收集器短;
    4. 并发清除(Concurrent Sweep,非 STW):清除老年代的死亡对象,释放内存,与用户线程并发执行,无 STW;
    • 注意:CMS 收集器的 “并发清除” 不会压缩内存,会产生内存碎片;当内存碎片过多时,会触发 “Full GC 降级”(用 Serial Old 收集器进行标记 - 整理,STW 时间长)。
    # (5)GC 后的内存分配
    • FGC 完成后,老年代空间被释放,后续新对象继续在 Eden 区分配,重复上述流程;
    • 若 FGC 后老年代仍无法容纳对象(如内存泄漏导致老年代对象持续增多),JVM 会抛出OutOfMemoryError: Java heap space。

    # 3. 关键特点

    • YGC 频率高、STW 时间短:新生代对象存活时间短,YGC 只需复制少量存活对象,STW 时间通常在 10-100 毫秒;
    • FGC 频率低、STW 时间长:老年代对象存活时间长,FGC 需处理大量对象,STW 时间可能达秒级,是性能优化的重点;
    • 分代回收效率高:基于对象存活周期的分代模型,使不同代采用最适合的 GC 算法(新生代用复制算法,老年代用标记 - 清除 / 标记 - 整理算法),提升 GC 整体效率。

    上次更新: 12/30/2025
    多线程 Future 的用法
    如何判断对象可以被回收

    ← 多线程 Future 的用法 如何判断对象可以被回收→

    最近更新
    01
    CPU 使用率较高排查和解决
    12-29
    02
    JVM OOM 问题如何排查和解决
    12-29
    03
    接口防刷怎么实现?
    12-29
    更多文章>
    Theme by Vdoing | Copyright © 2025-2026 Bohr-L's note
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式