news 2026/6/10 17:33:05

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【JVM】垃圾回收GC全套深度详解(大厂高频八股)

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


简介

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


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

1. 引用计数法

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

2. 可达性分析算法(Java虚拟机标准方案)

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

二、GC Roots包含哪些对象

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

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

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

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

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

2. 复制算法(Copy)

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

3. 标记-整理(Mark-Compact)

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

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

新生代适配复制算法

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

老年代适配标记-整理算法

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

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

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

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

七、什么是STW(Stop The World)

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

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

新生代收集器

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

老年代收集器

  1. Serial Old:Serial单线程老年代版本
  2. Parallel Old:Parallel Scavenge配套多线程老年代收集器
  3. CMS:并发低延迟收集器,减少STW时长,JDK8经典老年代收集器

整堆分代收集器(全堆管理)

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

九、三色标记法原理

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

三种颜色状态

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

并发标记两大问题

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

总结(面试速记版)

  1. 对象存活:HotSpot只用可达性分析,放弃引用计数(循环引用缺陷)
  2. GC Roots五大类:栈、static、常量、JNI、锁对象
  3. 三大算法:标记清除(碎片)、复制(快、利用率90%新生代)、标记整理(无碎片适配老年代)
  4. 晋升四条件:年龄15、动态年龄、大对象、Survivor存不下
  5. GC分级:Minor(新生代)、Major(老年代)、Full(全堆,尽量规避)
  6. STW:GC暂停业务线程,所有收集器都存在,只能缩短不能消除
  7. 收集器梯队:Serial/Parallel/CMS/G1/ZGC,延迟逐步提升
  8. 三色标记:白未扫、灰处理中、黑已完成;解决漏标保障并发安全
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 17:21:33

Mythos门控式推理架构:大模型自我觉察与能力调度新范式

1. 项目概述:一次被刻意“锁住”的能力跃迁如果你最近关注大模型前沿动态,大概率已经看到过“Anthropic’s Mythos”这个代号在技术圈小范围流传。它不是某个新发布的模型,也不是一篇公开论文的标题,而是一次发生在2024年中旬、由…

作者头像 李华
网站建设 2026/6/10 17:17:29

手把手调试RT-Thread的上下文切换:从汇编代码看线程如何‘无缝’接力

手把手调试RT-Thread的上下文切换:从汇编代码看线程如何‘无缝’接力在嵌入式实时操作系统中,线程间的上下文切换是最核心的机制之一。想象一下,当多个任务需要共享同一个CPU时,系统如何做到让每个任务都以为自己独占处理器&#…

作者头像 李华
网站建设 2026/6/10 17:15:37

别再傻傻分不清了!一文搞懂前缀、中缀、后缀表达式(附波兰表达式C++递归/栈解法)

从零掌握前缀、中缀与后缀表达式:算法竞赛必备的表达式求值精要在算法竞赛和编程面试中,表达式求值是一个经久不衰的经典问题。许多初学者第一次遇到波兰表达式这类概念时,往往会被前缀、中缀、后缀这些术语弄得晕头转向。更棘手的是&#xf…

作者头像 李华