Java 面试高频题:GC 到底回收了什么、怎么回收、啥时候回收?



小时候看《西游记》,最佩服的不是孙悟空,而是太上老君。为啥?他能炼丹!一炉子东西,能把杂质统统烧掉,留下最精华的"仙丹"。

其实 Java 的垃圾回收机制,就有点像太上老君的"炼丹炉"------在内存这座"丹炉"里,把没用的对象统统清理掉,只留下我们真正需要的"对象仙丹"。

面试故事开场:HR的一句话,把我问住了!

某天,是我在南京面试某十八线大厂 Java 高级工程师岗位的第五轮。前四轮都挺顺,技术栈、项目经历、架构设计、数据库优化,我答得游刃有余。

直到第五轮,面试官推了下眼镜,淡淡问了句:

"能不能聊聊 Java 的垃圾回收机制?重点说说有哪些垃圾收集器、什么时候触发 Full GC、你在项目中遇到过哪些 GC 问题?"

那一刻,我脑袋一热:"完了,这题目,我背是背过,但从没系统整理过!"

冷静下来,我决定用讲故事的方式,把我对 GC 的理解娓娓道来。

为什么要有垃圾回收机制?

Java 的设计初衷之一,就是让开发者不用手动管理内存

不像 C/C++ 要 malloc() 和 free(),Java 世界里,对象的生命管理由 JVM 全权负责,这就是"垃圾回收"(Garbage Collection,简称 GC)。

但要自动化,就要代价。GC 虽好,也会"卡顿"甚至"误杀"。所以我们得深刻理解它,才能用好它。

GC 的基本原理:谁才是"垃圾"?

垃圾回收的第一步,就是判断"哪些对象是垃圾"。

那怎么判断呢?JVM 提供了两种常见方法:

1. 引用计数法(已被淘汰)

每个对象有个引用计数器,谁引用它,计数 +1,谁不引用了,计数 -1,计数为 0 就回收。

问题是:循环引用无法解决!

举个例子:

A → B → A

A 和 B 相互引用,但实际没人再用它们了,计数却不是 0,GC 就永远不会清理它们。

所以这个方法早被淘汰。

2. 可达性分析(当前主流)

JVM 会从"GC Roots"出发,向下搜索所有能关联到的对象。

  • 如果某个对象从 GC Roots 没有任何引用链能连上,就判定为"死对象",可以被回收。

GC Roots 包括什么?

  • 虚拟机栈中引用的对象(如方法局部变量)
  • 方法区中类静态属性引用的对象
  • 方法区中常量引用的对象
  • 本地方法栈中的 JNI 引用(Native 方法)

Java 内存区域与 GC 关系

想搞懂 GC,就得先知道 GC 管的是哪部分内存。

JVM 把内存划成几块,但GC 只负责堆(Heap)和方法区(Metaspace)

堆又分成:

1、年轻代(Young Generation)

  • Eden 区
  • Survivor 区(From 和 To)

2、老年代(Old Generation)

垃圾回收又分为两种:

垃圾收集器全家桶,你了解几个?

每个 JVM 垃圾收集器都有"性格",面试时说出他们的特点,立马高级感拉满!

1. Serial 收集器(单线程)

  • 老古董,但稳定
  • 适用于客户端小程序

2. ParNew 收集器

  • Serial 的多线程版
  • 常配合 CMS 用于新生代

3. CMS 收集器(Concurrent Mark Sweep)

  • 以"并发+低停顿"著称
  • 四个阶段:初始标记 → 并发标记 → 重新标记 → 并发清除
  • 会导致内存碎片

4. G1 收集器(Garbage First)

  • JDK9 默认收集器
  • 把堆分成多个小块,局部收集,降低停顿
  • 老年代也能并发回收!

5. ZGC 和 Shenandoah(超低停顿)

  • 毫秒级停顿,适用于延迟敏感系统
  • 支持TB级堆,未来趋势

GC 的生命周期:一次垃圾回收是怎么发生的?

我们模拟一下一个对象从出生到"被回收"的过程:

  • 创建新对象,分配在 Eden 区。
  • 当 Eden 区满了,触发 Minor GC。
    • 幸存对象移入 Survivor 区。
  • 若对象经过多次 Minor GC 仍存活,晋升至老年代。
  • 老年代满了,触发 Full GC。
    • 回收整个堆,包括老年代和方法区。
  • 对象彻底 unreachable,被清理,空间被释放。

GC 问题排查经验:我踩过的坑!

之前在项目中遇到一次 频繁 Full GC 卡顿问题,用户页面卡得都以为系统崩了。

我用 jstat, jmap, jconsole 分析后,发现:

  • 新生代太小,频繁 Minor GC
  • 老年代回收不及时,触发 Full GC
  • 使用的是 CMS 收集器,出现了"Concurrent Mode Failure"

解决方案

  • 调大年轻代大小,降低 GC 频率
  • 切换 G1 收集器,降低 Full GC 停顿
  • 加入 GC 日志监控,提前预警

总结一下:面试中怎么答才加分?

如果你在面试中被问到"Java 垃圾回收机制",可以按这个顺序答:

  • 先总览 GC 的目的:自动化内存管理,提升开发效率
  • 再谈识别垃圾的方法:引用计数法 & 可达性分析
  • 说说内存结构:新生代 & 老年代,Minor GC & Full GC
  • 补充垃圾收集器特点:Serial、CMS、G1、ZGC 等
  • 最后加项目实战经历:GC 问题 + 排查 + 解决

END

你可能不常手动写 GC,但 GC 每天都在你程序背后默默工作。

你不理解它,它可能就让你程序"卡死"或"崩溃"。

但只要你愿意花 15 分钟,像小米我一样,画图、模拟、讲故事,GC 也能变得很温柔、很可控。

我是小米,一个喜欢分享技术的31岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号"软件求生",获取更多技术干货!

相关推荐
计算机毕设定制辅导-无忧学长16 分钟前
InfluxDB 集群部署与高可用方案(二)
java·linux·前端
SimonKing16 分钟前
Mysql分页:高效处理海量数据的核心技术
java·后端·程序员
寻星探路29 分钟前
常用排序方法
java·开发语言·算法
青云交32 分钟前
Java 大视界 -- 基于 Java 的大数据实时流处理在工业物联网设备故障预测与智能运维中的应用(384)
java·大数据·物联网·flink·设备故障预测·智能运维·实时流处理
半桔42 分钟前
【STL源码剖析】从源码看 vector:底层扩容逻辑与内存复用机制
java·开发语言·c++·容器·stl
洛卡卡了1 小时前
面试官问限流降级,我项目根本没做过,咋办?
后端·面试·架构
慕y2741 小时前
Java学习第一百零九部分——Jenkins(一)
java·学习·jenkins
ezl1fe1 小时前
RAG 每日一技(十四):化繁为简,统揽全局——用LangChain构建高级RAG流程
人工智能·后端·算法
悟能不能悟1 小时前
cdn是什么
java
amazingCompass1 小时前
Java 开发必备技能:深入理解与实战 IntelliJ IDEA 中的 VM Options
后端