【大白话说Java面试题 第66题】【JVM篇】第26题:介绍一下 G1 垃圾收集器?

📌 PDF :大白话说Java面试题 --- 02-JVM篇

第26题:介绍一下 G1 垃圾收集器

📚 回答:

  • 核心考点
    G1(Garbage First)是JDK 9+的默认垃圾收集器,设计目标是替代CMS ,在大堆内存(≥4GB)场景下实现可预测的停顿时间 ,同时避免内存碎片。面试需掌握其Region布局、停顿模型、与CMS的本质区别

1. G1 的核心设计思想
特性 说明
Region化堆内存 将堆划分为多个大小相等的Region(1~32MB,默认2048个),每个Region可动态扮演Eden、Survivor、Old、Humongous(大对象)角色
停顿预测模型 基于历史数据(每个Region的回收耗时)选择**高收益Region集合(CSet)**回收,使停顿时间可控
增量式回收 每次只回收部分Region,而非全堆,避免长时间STW
全局并发标记 并发标记存活对象,最终通过筛选回收阶段 复制存活对象到新Region,彻底消除碎片

2. G1 的内存布局(关键区别)

与传统分代GC对比

  • 传统(Parallel/CMS):物理连续分区(Eden、S0、S1、Old)
  • G1:逻辑分代 + 物理Region隔离,某Region可以从未分代动态切换

大对象(Humongous Region)

  • 对象大小 > Region大小的50%
  • 存放在连续的Humongous Region中(H区)
  • 回收时效率低,需避免过多大对象

3. G1 的工作阶段(面试详版)
阶段 类型 主要动作 是否STW 备注
初始标记 Young GC期间附属 标记GC Roots直接可达对象 借用Young GC停顿,几乎无额外开销
并发标记 并发 从GC Roots遍历对象图,计算每个Region存活对象 标记过程中应用线程继续运行
最终标记 并发+短暂STW 处理SATB(Snapshot-At-The-Beginning)漏标对象 修正并发标记期间的引用变化
筛选回收 混合模式 选择回收价值最高的Region(CSet),复制存活对象 可并行,停顿时间由MaxGCPauseMillis控制
Full GC 后备 单线程Serial Old回收全堆 是(很长) 当并发回收赶不上对象分配时触发

关键点

  • SATB(Snapshot-At-The-Beginning):G1通过写屏障维护并发标记开始时对象图的快照,防止漏标。
  • Mixed GC:筛选回收阶段会同时回收年轻代+部分老年代Region。

4. G1 停顿时间模型(面试核心)

参数

bash 复制代码
-XX:MaxGCPauseMillis=200   # 目标200ms(默认值),不是硬性保证,G1会尽量逼近
-XX:GCPauseIntervalMillis  # 停顿间隔,默认未设置

实现机制

  1. G1会记录每个Region的历史回收耗时(平均、标准差等)
  2. 年轻代大小动态调整:若历史停顿时间 > 目标,缩小年轻代;否则扩大
  3. 筛选回收时,按垃圾/回收耗时比对Region排序,从高到低选入CSet,直到预估总时间接近目标值

误区 :设置MaxGCPauseMillis太小(如10ms)会导致年轻代极小,Young GC频繁,吞吐下降。


5. G1 vs CMS 深度对比
对比维度 G1 CMS
堆布局 Region化,逻辑分代 物理连续分代(Eden+S0+S1+Old)
碎片问题 无碎片(复制整理) 严重碎片(标记-清除)
停顿时间 可预测,可控制(默认200ms) 不可控,随老年代碎片恶化
Full GC触发 并发回收赶不上分配时 碎片导致晋升失败/并发模式失败
CPU敏感度 中等 (并发标记占CPU)
内存占用 每个Region有Remembered Set(RS)额外占用5%~10%堆内存 较低
大对象处理 Humongous Region(效率低) 直接进老年代(易导致碎片)
JDK版本 JDK 7u4引入,JDK 9+默认 JDK 9废弃,JDK 14移除

6. G1 常用调优参数
参数 含义 建议值 风险提示
-XX:MaxGCPauseMillis 目标停顿时间 100~300ms 太小导致频繁GC
-XX:G1HeapRegionSize Region大小 自动(1/2/4/8/16/32MB) 手动设需是2的幂
-XX:InitiatingHeapOccupancyPercent 触发并发标记的老年代占用比例 默认45% 过低频繁并发标记,过高易Full GC
-XX:G1NewSizePercent 年轻代最小值(占堆百分比) 默认5% 太小导致频繁Young GC
-XX:G1MaxNewSizePercent 年轻代最大值 默认60% 太大可能导致老年代回收赶不上
-XX:ParallelGCThreads 并行GC线程数 默认CPU数5/8 容器内需设置≤CPU核数
-XX:ConcGCThreads 并发GC线程数 默认ParallelGCThreads的1/4 并发标记阶段占CPU

7. G1 典型问题与排查

问题1:Mixed GC后仍有大量老年代内存未回收,持续Full GC

  • 根因:InitiatingHeapOccupancyPercent 过大导致并发标记触发晚,老年代堆积过多
  • 解决:调小至35~40%,或增大MaxGCPauseMillis

问题2:Humongous对象分配导致频繁Full GC

  • 根因:大对象(>Region 50%)分配后,回收代价高
  • 解决:应用层拆分大对象,或增大Region(-XX:G1HeapRegionSize=32m

问题3:RS(Remembered Set)占用内存过高

  • 根因:Region间引用复杂(跨区引用多)
  • 解决:正常现象,限制G1堆内存<16GB(JDK 8之前),或升级JDK(优化了RS压缩)

8. 面试官追问示例

Q1:G1 一定比 CMS 好吗?

A:不是。CMS在堆内存<4GB、停顿不敏感的场景仍然高效。G1的RS维护占用额外内存(~10%),小堆上得不偿失。

Q2:G1 的 Mixed GC 频率如何控制?

A:由InitiatingHeapOccupancyPercent控制:当老年代占用超过此阈值时,触发并发标记,标记完成后触发Mixed GC。Mixed GC会持续多次,每次回收部分老年代Region。

Q3:G1 能完全避免 Full GC 吗?

A:不能。典型情况:

  • 并发模式失败(老年代未标记完就满了)
  • 晋升失败(Survivor/老年代Region无空间放晋升对象)
  • 大对象分配(找不到连续Humongous Region)

Q4:G1 中 Young GC 也是 STW 的,为什么说 G1 低延迟?

A:因为Young GC虽然STW,但G1通过动态调整年轻代大小,让每次Young GC停顿时间可控 (接近MaxGCPauseMillis)。而Parallel GC年轻代固定,停顿可能更长。

Q5:G1 适用于多大堆内存?

A:官方推荐6GB~64GB。大于64GB推荐ZGC(停顿<10ms),小于6GB可用Parallel或G1(但RS内存开销明显)。


💡 面试官想要的满分总结

"G1是Region化、增量式、可预测停顿的垃圾收集器,通过复制整理消除碎片。核心机制包括:堆分为等大小Region、Remembered Set避免全局扫描、SATB保证并发标记正确性、根据历史数据选择高收益Region回收。

适用堆4~64GB,调优核心是MaxGCPauseMillis(默认200ms)和InitiatingHeapOccupancyPercent(默认45%)。

与CMS相比,G1无碎片、停顿可控,但内存占用略高。大堆场景下,G1优于CMS;超大堆(>64GB)应选ZGC/Shenandoah。"


觉得对您有帮助,麻烦 点点关注啦 ,您的关注是我创作的最大动力~ 🎯

相关推荐
雨落在了我的手上1 小时前
初识java(八):数组的定义与使用
java·开发语言
贵州晓智信息科技1 小时前
曼德勃罗集的 Three.js 实现
开发语言·javascript·ecmascript
xiaoshuaishuai81 小时前
C# CUDA 到 OpenCL 迁移
开发语言·windows·c#
asdfg12589631 小时前
一文理解“架构思维”
java·软件工程·软件开发·架构思维
AI科技星1 小时前
基于平行素数对等腰梯形网格拓扑的完备性证明哥德巴赫猜想1+1
c语言·开发语言·网络·量子计算·agi
聆风吟º1 小时前
【C标准库】深入理解C语言 isdigit函数详解:判断字符是否为数字
c语言·开发语言·库函数·isdigit
故事和你911 小时前
洛谷-【图论2-4】连通性问题1
开发语言·数据结构·c++·算法·动态规划·图论
RSCompany1 小时前
Frida 17 以后 Python API 跑旧版 JS 报 Java is not defined ?一行 import 直接恢复 Frida 16 体验
开发语言·python·逆向·hook·frida·android逆向·frida17
云烟成雨TD1 小时前
Spring AI Alibaba 1.x 系列【57】SAA Admin 前后端技术栈与分层设计详解
java·人工智能·spring
快乐的哈士奇1 小时前
对话框打字机效果:Vur + Java/Python 实现
java·开发语言·python