面试被问 G1 GC 懵了?记住这几点就能完美回答!



小米来咯!这次咱们聊聊一个 Java 面试中出场率极高的"硬菜"------G1 垃圾回收器(Garbage-First GC) 。作为一名在互联网大厂摸爬滚打了多年的 Java 工程师,我可是亲身见证了从 CMS 到 G1 的演进,也踩过不少 GC 的坑。今天我们就来系统、轻松、故事化地把 G1 GC 讲清楚,既能帮你面试拿下高分,也能让你写代码更安心。

一个真实的"救火"故事:我和 G1 GC 的第一次亲密接触

那是三年前的一个深夜,线上交易系统突然响应变慢,甚至偶尔还有超时报警。我刚洗完澡准备睡觉,领导电话就打了过来:"小米,赶紧上来看一下,线上服务抖得厉害,GC 时间飙上去了!"

我一登录,jstat 一查,果不其然:Full GC 十几秒一次,每次暂停 5~6 秒,简直是大型事故现场。我们的老服务还在用 CMS,那会儿堆内存给到了 20G,GC 时老年代碎片太多,导致频繁 Full GC,系统抖得不行。

我当时果断切换到了 G1 GC,经过一番配置调优,系统瞬间稳定了。从那以后,我就成了 G1 的死忠粉。

G1 GC 是什么?它想解决什么问题?

我们先来看看 G1 是为了解决谁的问题而生的。

在 G1 出现之前,老牌的 CMS GC 用得很多,但 CMS 有三个致命缺陷:

  • 无法整理内存碎片:老年代回收后留下的碎片可能导致Promotion Failed。
  • 并发阶段复杂:容易触发Concurrent Mode Failure,最终退化成 Full GC。
  • GC 时间不可控:无法精准控制每次停顿的时间。

而 G1 GC 就是为了解决这些问题而诞生的。

它的名字就很有意思:Garbage-First,意思是"优先回收垃圾多的地方"。听起来是不是有点像那个只抓重点抄作业的聪明同学?

G1 GC 的内存布局:Region 来了!

传统的堆内存分为:年轻代(Young)+ 老年代(Old) ,其中年轻代又分 Eden 和 Survivor,但 G1 的结构有了重大改变。

G1 把整个堆划分成了若干个大小相同的 Region(比如 1~32MB 一个块),每个 Region 可以承担不同的角色:

  • Eden Region:存放新对象
  • Survivor Region:幸存者对象
  • Old Region:晋升的老对象
  • Humongous Region:专门放"大对象"(超过 50% Region 大小)

这种设计有啥好处?灵活!不再像 CMS 一样"前一块儿是年轻代,后一块儿是老年代",而是可以动态调整内存使用

G1 GC 的核心流程:四步走

G1 的 GC 类型主要有四种:Young GC、Mixed GC、Full GC、Concurrent Cycle。核心流程分为以下四步:

  1. Young GC(年轻代收集)

和其他 GC 类似,G1 每次 Minor GC 时只收 Eden 区域,把幸存对象复制到 Survivor 或晋升到 Old。暂停时间短,效率高。

  1. Concurrent Marking(并发标记阶段)

当老年代使用率达到一定阈值(比如 45%)时,G1 会启动一次"并发标记":

  • 初始标记:STW(Stop The World),标记 GC Roots 可达对象
  • 并发标记:不 STW,扫描整个堆,识别出存活对象
  • 最终标记:STW,处理 RSet 更新
  • 筛选回收:确定要回收哪些 Region,准备 Mixed GC
  1. Mixed GC(混合收集)

这是 G1 最"聪明"的一招!不像 CMS 只能收年轻代,G1 会同时收回年轻代和部分老年代中的高回收收益 Region

通过精细控制 Region 的选择,G1 可以让 GC 更加高效,而且 暂停时间可控(这是面试高频点!)。

  1. Full GC(最后的杀招)

当 G1 实在没招了,比如 Humongous 对象太多,GC 压力过大,它会触发 Full GC。这个过程依然是 STW,而且比 CMS 快,但我们要尽量避免它。

G1 GC 的最大亮点:暂停时间可控

这是 G1 最吸引面试官的点:可以指定最大停顿时间(Pause Time Goal)

比如:

-XX:MaxGCPauseMillis=200

意思是:我希望每次 GC 暂停不超过 200 毫秒。G1 会努力达成这个目标(但不能百分百保证)。

它通过预估 GC 成本、回收收益,来"聪明地"选择回收哪些 Region,从而在性能和响应之间找平衡。

那些你可能忽略的 G1 黑科技

1、Remembered Set(RSet)

G1 不再像 CMS 那样全扫描,而是维护一个每个 Region 的"指针引用表",可以只扫描必要的区域,减少开销。

2、Card Table + SATB 写屏障

为了支持并发标记,G1 引入了快照式读屏障(Snapshot-At-The-Beginning) ,配合 Card Table 实现对引用的精确跟踪。

3、Humongous Object 分配优化

G1 会优先处理大对象,但如果大对象太多,容易触发 Full GC。可以通过调整 -XX:G1HeapRegionSize 和 -XX:G1HeapWastePercent 来优化。

常见 G1 GC 面试问题梳理(建议收藏)

  • G1 和 CMS 的本质区别是什么?
  • G1 如何实现暂停时间可控?
  • G1 的内存结构为什么要划分为 Region?
  • G1 如何解决 CMS 的内存碎片问题?
  • G1 为什么 Mixed GC 是重点?
  • 什么是 Remembered Set?SATB 是干嘛的?
  • G1 是不是就不需要 Full GC?
  • G1 的调优参数有哪些关键的?

总结:为什么我推荐使用 G1 GC?

G1 不是银弹,但它适合这些场景:

  • 堆内存大于 4GB 的应用
  • 对响应时间有要求(暂停时间敏感)
  • 容易出现 CMS 碎片、Concurrent Mode Failure 的服务

从 Java 9 开始,G1 就成了默认 GC,说明它的稳定性已经得到了社区认可。

彩蛋时间:一条最能让你面试加分的 G1 表述

"G1 是一种面向服务端的大内存垃圾回收器,它通过将堆划分为 Region,实现并发标记+分代回收,支持用户设定最大停顿时间,从而在吞吐量与响应时间之间取得平衡。"

看到没?这一段背下来,保证面试官心里暗暗点赞!

END

好了,今天的分享就到这啦,G1 GC 虽然底层原理不少,但只要我们理清"Region + Mixed GC + Pause Control"这三大核心,就已经掌握了它的 80%!

你还想听我讲哪个 GC?ZGC?Shenandoah?留言区告诉我呀~

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

相关推荐
ahauedu7 分钟前
jar命令提取 JAR 文件
java·jar
青岛少儿编程-王老师24 分钟前
CCF编程能力等级认证GESP—C++1级—20250628
java·开发语言·c++
lifallen1 小时前
KRaft 角色状态设计模式:从状态理解 Raft
java·数据结构·算法·设计模式·kafka·共识算法
LittleLoveBoy1 小时前
Java HashMap key为Integer时,遍历是有序还是无序?
java·开发语言
经典19921 小时前
Java 设计模式及应用场景
java·单例模式·设计模式
IguoChan1 小时前
9. Redis Operator (2) —— Sentinel部署
后端
ansurfen2 小时前
耗时一周,我的编程语言 Hulo 新增 Bash 转译和包管理工具
后端·编程语言
库森学长2 小时前
索引失效的场景有哪些?
后端·mysql·面试
oioihoii2 小时前
Visual Studio C++编译器优化等级详解:配置、原理与编码实践
java·c++·visual studio
没有羊的王K2 小时前
SSM框架——Day4
java·开发语言