欢迎光临
我们一直在努力

【JVM】垃圾回收GC全套深度详解(大厂高频八股)

大家好,我是程序员二叉。


简介

本文一次性讲透对象存活判定、GC Roots、三大GC回收算法、分代回收设计逻辑、对象晋升规则、Minor/Major/Full GC区别、STW、主流垃圾收集器、三色标记法等全套核心考点。欢迎点赞收藏关注。


一、如何判断对象是否存活?引用计数 & 可达性分析

1. 引用计数法

  • 实现原理
    给每个对象分配一个引用计数器,对象被引用时计数器+1,引用失效释放时计数器-1;计数器数值为0代表对象可回收。
  • 优点
    实现逻辑简单、判定响应速度快,回收时无停顿压力。
  • 致命缺陷
    无法解决对象循环引用场景,两个对象互相引用,计数器永远无法归零,造成内存泄漏,因此HotSpot JVM并未采用此方案。
  • 2. 可达性分析算法(Java虚拟机标准方案)

  • 实现原理
    以固定的GC Roots作为起始根节点,向下遍历整个引用链路;遍历过程中能连通到的对象标记为存活,无法抵达的对象判定为垃圾可回收。
  • 优点
    完美规避循环引用问题,判定精准稳定;是HotSpot、Android ART虚拟机统一使用的存活判断方式。

  • 二、GC Roots包含哪些对象

    作为可达性分析起点、永远不会被回收的根对象,一共5大类:

  • 虚拟机栈(栈帧局部变量表)中引用的对象
  • 方法区中static静态变量引用的对象
  • 方法区中运行时常量池引用的常量对象
  • 本地方法栈中JNI Native方法引用的对象
  • 持有synchronized同步锁的对象

  • 三、三大垃圾回收算法及各自优缺点

    1. 标记-清除(Mark-Sweep)

  • 执行流程:先遍历标记所有存活对象 → 统一清理未标记的垃圾对象
  • 优点:实现简单,不需要额外预留内存空间
  • 缺点:
    • 两次全堆扫描,整体回收效率偏低
    • 清理后产生大量不连续内存碎片,大对象分配容易OOM
  • 2. 复制算法(Copy)

  • 执行流程:把内存划分两块对等区域,只使用其中一块;GC时将存活对象完整复制到空白区域,复制完成直接清空原整块内存
  • 优点:复制过程无内存碎片、回收速度极快
  • 缺点:内存利用率天然只有50%,存活对象数量多的时候复制开销巨大
  • 3. 标记-整理(Mark-Compact)

  • 执行流程:第一步标记存活对象;第二步将所有存活对象向内存一端紧凑移动;最后清空边界以外全部垃圾空间
  • 优点:无内存碎片、内存利用率100%,适合存活率高的内存区域
  • 缺点:需要移动大量存活对象,整体耗时更长、效率偏低

  • 四、新生代用复制算法,老年代用标记整理的原因

    新生代适配复制算法

  • 新生代对象生命周期极短,98%左右的对象Minor GC都会直接消亡,存活对象占比极低
  • 复制少量存活对象开销很小,回收速度快,几乎无碎片
  • HotSpot优化:采用Eden:From:To=8:1:1布局,实际内存利用率高达90%,规避原生复制算法50%利用率的短板
  • 老年代适配标记-整理算法

  • 老年代对象存活率极高、生命周期长,大量存活对象如果用复制算法,拷贝成本极高
  • 老年代经常存放大对象,一旦产生内存碎片极易分配失败触发Full GC;标记整理压缩后空间连续,完美适配大对象分配需求

  • 五、新生代对象晋升到老年代的四大条件

  • 年龄阈值达标(默认15)
    对象每熬过一次Minor GC,年龄计数器+1;年龄达到-XX:MaxTenuringThreshold默认值15,自动晋升老年代。
  • 动态年龄判定
    Survivor区中,相同年龄所有对象占用内存总和 > Survivor空间一半;大于等于该年龄的全部对象直接晋升,无需等到15岁。
  • 超大对象直接分配老年代
    对象大小超过-XX:PretenureSizeThreshold阈值,不走新生代,直接创建在老年代,避免Eden反复复制大数组/大实例。
  • 分配担保机制
    Minor GC后存活对象总量大于Survivor剩余容量,无法放入Survivor,存活对象直接转移到老年代。

  • 六、Minor GC、Major GC、Full GC定义与触发条件

    1. Minor GC

    • 回收范围:仅新生代(Eden+两块Survivor)
    • 触发条件:Eden内存空间填满
    • 特点:执行频繁、停顿时间短、速度快

    2. Major GC

    • 回收范围:仅老年代区域
    • 触发条件:老年代内存占用接近上限
    • 特点:速度远慢于Minor GC,常伴随一次Minor GC一起发生

    3. Full GC

    • 回收范围:整个堆(新生代+老年代)+ 元空间
    • 触发条件:
    • 手动调用System.gc()
    • 老年代空间不足
    • Minor GC担保失败
    • 元空间Metaspace内存耗尽
    • 特点:停顿时间最长、性能损耗最大,线上业务要极力减少Full GC频率

    七、什么是STW(Stop The World)

  • 定义
    垃圾回收执行标记、复制、整理操作时,所有Java业务用户线程全部暂停冻结,只有GC后台线程允许运行。
  • 存在意义
    保证可达性分析标记阶段,对象之间的引用关系不会被业务线程修改,防止标记错乱、存活对象误回收。
  • 优化方向
    没有任何收集器能彻底消除STW;G1、ZGC、Shenandoah等低延迟收集器的核心目标就是尽可能压缩STW停顿时长。

  • 八、主流常用垃圾收集器分类

    新生代收集器

  • Serial:单线程收集器,客户端小程序、嵌入式设备使用
  • ParNew:Serial多线程优化版,曾配合CMS使用
  • Parallel Scavenge:主打高吞吐量,关注程序整体运行效率
  • 老年代收集器

  • Serial Old:Serial单线程老年代版本
  • Parallel Old:Parallel Scavenge配套多线程老年代收集器
  • CMS:并发低延迟收集器,减少STW时长,JDK8经典老年代收集器
  • 整堆分代收集器(全堆管理)

  • G1:分区式收集器,可预测停顿时间,JDK9之后官方默认收集器
  • ZGC:超低延迟收集器,百微秒级STW,大内存堆场景首选
  • Shenandoah:RedHat推出的低延迟收集器,和ZGC定位一致

  • 九、三色标记法原理

    三色标记是CMS、G1、ZGC等并发GC用来做可达性标记的核心算法,用来拆分标记阶段,降低STW时长。

    三种颜色状态

  • 白色:初始状态,尚未扫描访问的对象,最终白色对象判定为垃圾
  • 灰色:已经被扫描到,但自身持有的子引用对象还未全部遍历处理完成
  • 黑色:自身已扫描完毕,所有下级引用全部遍历完成,标记为稳定存活对象
  • 并发标记两大问题

  • 浮动垃圾:并发过程中新产生的垃圾,本次GC无法回收,留到下一轮GC处理,无安全风险
  • 对象漏标(致命):灰色对象断开黑色引用、同时引用白色对象,会导致存活白色对象被误回收;解决方案:CMS用增量更新、G1/ZGC用原始快照SATB

  • 总结(面试速记版)

  • 对象存活:HotSpot只用可达性分析,放弃引用计数(循环引用缺陷)
  • GC Roots五大类:栈、static、常量、JNI、锁对象
  • 三大算法:标记清除(碎片)、复制(快、利用率90%新生代)、标记整理(无碎片适配老年代)
  • 晋升四条件:年龄15、动态年龄、大对象、Survivor存不下
  • GC分级:Minor(新生代)、Major(老年代)、Full(全堆,尽量规避)
  • STW:GC暂停业务线程,所有收集器都存在,只能缩短不能消除
  • 收集器梯队:Serial/Parallel/CMS/G1/ZGC,延迟逐步提升
  • 三色标记:白未扫、灰处理中、黑已完成;解决漏标保障并发安全
  • 赞(0)
    未经允许不得转载:171主机测评 » 【JVM】垃圾回收GC全套深度详解(大厂高频八股)
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址