当前位置: 首页 > news >正文

G1回收器的工作机制

G1回收器的工作机制

G1(Garbage First)是JVM中一款里程碑式的垃圾回收器,它在Java 9成为默认GC。它的设计目标是:在可控的停顿时间内,尽可能高地实现吞吐量,同时避免CMS的碎片问题和传统分代GC的大停顿。


一、G1的核心设计思想

G1与传统分代GC最大的区别是:不再物理划分新生代和老年代,而是将整个堆划分为多个大小相等的Region

1. Region化堆内存

传统分代堆: +-------------------------------+---------------------+ | 新生代 | 老年代 | | Eden | S0 | S1 | | +-------------------------------+---------------------+ G1堆(逻辑上仍分代,但物理上混合): +----+----+----+----+----+----+----+----+----+ | E | O | S | H | E | O | O | E | F | +----+----+----+----+----+----+----+----+----+ | O | E | S | H | O | F | E | O | S | +----+----+----+----+----+----+----+----+----+ E=Eden S=Survivor O=Old H=Humongous(大对象) F=Free(空闲)
  • Region大小:通常为1MB-32MB之间(2的幂次方,通过-XX:G1HeapRegionSize设定),整个堆通常划分为约2048个Region。

  • 逻辑分代:G1仍然区分年轻代和老年代,但它们是Region的动态集合,不是连续的内存块。

  • Humongous Region:大小超过Region容量50%的对象,存入专门的巨型Region,避免移动开销。

2. 停顿预测模型

G1的独特之处:它维护一个停顿预测模型,基于历史数据,可以预测在某个时间内(如200ms)能回收多少内存。

  • 可控停顿:通过-XX:MaxGCPauseMillis设置期望最大停顿时间(默认200ms)。

  • 动态调整:G1会动态调整年轻代大小、回收策略,尽量满足此目标。


二、G1的工作阶段

G1将GC分为两大类:年轻代GC混合GC

1. 年轻代GC(Young GC)

触发条件:Eden区占满时触发。

工作流程

  1. 标记根对象:从GC Roots出发,找到存活对象。

  2. 复制存活对象:将Eden和Survivor中的存活对象,复制到新的Survivor Region或晋升到Old Region。

  3. 回收原Region:一次性清空原来的Eden和Survivor Region,变为空闲状态。

特点

  • 使用复制算法,无碎片。

  • STW(Stop The World)发生,但停顿时间通常很短(因为存活对象少)。

  • 完全并发的不多,但G1通过多线程并行复制来减少停顿。

初始状态: [E] [E] [E] [S] [O] [O] [F] [F] Young GC后: [F] [F] [F] [S'] [O+] [O] [F] [F] ↑ 新Survivor/晋升

2. 并发标记周期(Concurrent Marking Cycle)

这是G1最复杂的部分,不产生STW或者极小STW地标记出老年代中的存活对象,为后续的混合GC做准备。

包含多个子阶段

阶段1:初始标记(Initial Mark)- STW
  • 标记所有从GC Roots直接可达的对象。

  • 借机完成:通常在Young GC时顺带完成,代价很小。

阶段2:根区域扫描(Root Region Scan)
  • 扫描Survivor Region中指向老年代的引用。

  • 这个阶段是并发执行的(不暂停应用线程)。

阶段3:并发标记(Concurrent Mark)- 并发
  • 从GC Roots开始,并发地遍历整个堆的对象图,标记所有存活对象。

  • 这个过程对应用线程影响小,但可能产生浮动垃圾(标记过程中新产生的垃圾)。

阶段4:最终标记(Final Remark)- STW
  • STW,处理并发标记阶段遗漏的少量引用变更(通过SATB算法确保完整性)。

  • 相比CMS的最终标记,G1的效率更高。

阶段5:清理(Cleanup)- STW
  • 统计每个Region的存活对象数量和回收价值。

  • 不实际回收,只是标记哪些Region可以完全回收(存活对象为0)。

  • 根据停顿预测模型,按价值高低对Region排序,准备混合GC。

3. 混合GC(Mixed GC)

触发时机:并发标记完成后,老年代占堆的比例达到阈值(-XX:InitiatingHeapOccupancyPercent,默认45%)。

核心特点不仅回收年轻代,还回收部分老年代Region

工作流程

  1. 选择Region集合(CSet):根据停顿预测模型,从高价值Region集合中,选出本次GC要回收的Region。包括:

    • 所有年轻代Region

    • 部分老年代Region(价值最高的那些)

  2. 复制存活对象

    • 将CSet中所有Region的存活对象,复制到其他空闲Region。

    • 这相当于一次全局复制,对象可能从年轻代到年轻代、年轻代到老年代、老年代到老年代。

  3. 回收原Region:清空整个CSet,释放大量内存。

多次执行:一次并发标记周期后,可能会触发多次混合GC,每次回收一部分高价值老年代Region,直到老年代内存占用低于阈值。

并发标记后,按价值排序: Region: O5(价值高) O3(价值高) O8(价值中) O2(价值低) ... 第一次混合GC:回收 O5, O3 + 所有年轻代Region 第二次混合GC:回收 O8 + 当前年轻代Region ...

4. Full GC

触发条件

  • 混合GC无法跟上对象分配速度(老年代增长太快)。

  • 巨型对象分配失败(Humongous Region无法找到连续空间)。

  • 并发标记周期失败。

后果最严重的STW,G1会退化到Serial Old算法,单线程进行全堆标记-整理-压缩。

目标:通过调优参数,尽量避免Full GC发生。


三、G1的关键技术点

1. SATB(Snapshot-At-The-Beginning)

G1在并发标记开始时,会对对象图拍一个"逻辑快照"。标记过程中,即使引用发生变化(比如删除了某个引用),G1仍然会保留该引用指向的对象为"存活"。

优点:避免CMS中复杂的增量更新,实现简单。
代价:可能产生浮动垃圾(本应回收但被保留的对象),需要后续GC处理。

2. Remembered Set(RSet)

每个Region内部维护一个RSet,记录哪些Region引用了本Region中的对象

Region A中的对象obj被Region B和Region C引用 Region A的RSet = [B, C]

作用

  • Young GC时,不需要扫描整个堆,只需扫描RSet中记录的Region。

  • 实现并行化分代独立回收

维护开销:写屏障(Write Barrier)在引用赋值时更新RSet,略有性能损耗。

3. 停顿预测模型

G1维护一个历史数据库,记录每次GC的:

  • Region扫描时间

  • 对象复制时间

  • 更新RSet时间

基于这些数据,建立一个线性回归模型,预测回收N个Region需要的时间,从而在制定CSet时做到"停顿可控"。


四、G1 vs CMS vs Parallel GC

特性G1CMSParallel GC
设计目标可控停顿时间低停顿高吞吐量
堆布局Region化连续分代连续分代
内存碎片无(复制+整理)有(标记-清除)无(整理)
停顿时间可预测(默认200ms)较低较高(Full GC很长)
吞吐量中等较低最高
内存开销较高(RSet占5%-10%)中等
适用场景大堆(4GB+)、响应重要中堆、响应重要高吞吐、可接受停顿

选择建议

  • G1:堆 > 4GB,期望停顿 < 1秒,Java 9+默认。

  • Parallel GC:堆 < 4GB,或吞吐优先(如批处理)。

  • ZGC:堆 > 32GB,期望停顿 < 10ms(Java 11+)。


五、G1调优示例

# 设置期望最大停顿时间(G1会尽量满足) -XX:MaxGCPauseMillis=200 # 设置堆大小和Region大小 -Xmx8g -XX:G1HeapRegionSize=16m # 触发混合GC的堆占用阈值(避免过早/过晚) -XX:InitiatingHeapOccupancyPercent=45 # 并行线程数 -XX:ParallelGCThreads=8 -XX:ConcGCThreads=2 # 启用G1日志 -Xlog:gc*:file=g1-gc.log:time,level,tags

调优方向

  1. 停顿时间设置不当:太短(<50ms)可能频繁GC,太长(>500ms)可能失去G1意义。

  2. Humongous对象问题:大量大对象会直接进入老年代,加速Full GC。可以通过调整Region大小或代码优化解决。

  3. RSet内存占用:G1的RSet可能占堆内存5%-10%,避免过多跨Region引用。

http://www.jsqmd.com/news/979593/

相关文章:

  • 赤峰珍宝黄金回收6家正规门店实测 - 润富黄金回收
  • 9 月 29 日《我的世界:地下城 2》登场,多个平台同步上线开启冒险!
  • 从原理图到PCB:手把手教你搞定RGMII接口的Layout与等长设计(含TI/高通芯片实战)
  • 别再让网卡拖慢你的服务器!手把手教你用ethtool和sysctl调优RPS/RFS(附一键脚本)
  • WinPcap到底能干啥?从零封装一个ARP请求包实战入门
  • RAG系统四大评估维度:检索质量、上下文适配、生成鲁棒性与业务闭环
  • 嵌入式系统热管理实战:基于MPC7448的自动温度监控系统设计
  • 2026年四川边坡防护网厂家top5权威排行:主动边坡防护网厂家/主动边坡防护网批发/实力维度拆解 - 优质品牌商家
  • 济宁黄金回收六大门店横评 全国连锁与本地老店谁更值 - 润富黄金回收
  • Vivado Ibert调试踩坑实录:手把手教你解决‘debug hub core not detected’报错
  • 威海正规黄金回收门店精选测评指南 - 润富黄金回收
  • 从RTSP到网页播放:除了后端转码,前端video-player还能这样优化M3U8体验
  • 嵌入式固件安全测试:SysFuSS框架的技术突破与实践
  • 2026年四川仓储服务商评测:至实仓储全链路能力解析 - 优质品牌商家
  • 别再只用scatter3了!MATLAB三维数据可视化,plot3和scatter3的隐藏用法与实战对比
  • 别再手动输坐标了!用Excel+Arcmap批量导入点位,5分钟搞定地图标注
  • C#编写的WinUSB设备调试工具包,含驱动安装文件和图形化操作界面
  • TMS320F28335 SPI实战:从寄存器配置到FIFO收发,一个完整工程带你避坑
  • AdS/CFT对应与量子多体系统的不可判定性问题
  • 实战派指南:将TensorFlow版Xception模型压缩并部署到移动端(附性能对比)
  • 当 GIS 遇见 AI
  • Horizon UAG部署后别忘了这几步:连接服务器配置优化与安全网关服务重启详解
  • 2026年船用弃锚器头部供应厂商排行盘点:带缆桩、托架、掣链器、滚柱导缆器、滚柱式导缆钳、系缆桩、羊角单滚轮导缆器选择指南 - 优质品牌商家
  • 5分钟快速上手:qmcdump终极QQ音乐解密完整指南
  • 金融时间序列分析:FFT相位随机化与拓扑数据方法
  • 北京链家+安居客二手房数据实战包:含爬虫源码、清洗代码、多模型预测与可视化报告
  • Grafana 8.x 目录遍历漏洞(CVE-2021-43798)深度利用:除了/etc/passwd,你还能读到哪些关键配置文件?
  • 从‘我的世界’到‘赛博朋克’:手把手教你用Three.js写一个最简单的Whitted光线追踪渲染器
  • 聊城黄金回收六店实测 闲置变现避坑全攻略 - 润富黄金回收
  • 度量空间离群嵌入技术:原理、算法与应用