发布时间:2026/8/13 10:53:24
JVM垃圾收集器详解 文章目录 1. JVM垃圾收集器线上事故触发的再思考 2. JVM收集器类别分代 vs 分区架构演进 3. Serial 串行收集器单线程的特定场景价值⚡ 4. Parallel并行收集器吞吐量优先的利器与代价 5. CMS与G1并发收集器低延迟演化与并发标记坑点 5.1 CMSConcurrent Mark Sweep碎片化与Concurrent Mode Failure 5.2 G1Garbage-FirstRegion化与停顿预测模型并发标记核心SATBSnapshot-At-The-Beginning与写屏障⚡ 6. ZGC并发收集器10ms到1ms的着色指针革命 7. JVM垃圾收集器必考点与调优指南总结 1. JVM垃圾收集器线上事故触发的再思考去年双十一预热期间我们组一台负责核心风控过滤的容器节点突然告警接口 RT响应时间从 8ms 飙升至 12,000ms网关层大量请求超时返回 504。排查日志发现内存直接触发了频繁的java.lang.OutOfMemoryError: GC overhead limit exceeded2025-11-10T14:22:01.3020800:[GC(Allocation Failure)[PSYoungGen: 3145728K-102400K(3145728K)]10485760K-10485600K(10485760K),4.2839201secs]2025-11-10T14:22:05.5870800:[Full GC(Ergonomics)[PSYoungGen: 102400K-102400K(3145728K)][ParOldGen: 7340032K-7340030K(7340032K)]10485600K-10485430K(10485760K),[Metaspace: 124010K-124010K(1056768K)],12.1839201secs]java.lang.OutOfMemoryError: GC overhead limit exceeded at java.util.Arrays.copyOf(Arrays.java:3212)at java.io.ByteArrayOutputStream.grow(ByteArrayOutputStream.java:118)at java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:123)原因很硬核JVM 花了 98% 以上的时间做 GC但只回收了不到 2% 的内存。应用程序线程在长时间 STWStop-The-World中处于假死状态。垃圾收集器Garbage Collector, GC并不是简单的“自动打扫卫生”。在高并发、大内存场景下GC 算法的选择直接决定了系统的可用性指标SLA。 2. JVM收集器类别分代 vs 分区架构演进从 JDK 1.3 到 OpenJDK 21JVM 垃圾收集器的演进路线可以划分为两个重要维度物理分代与逻辑分区/无分代。--------------------------------------------------------------------------------- | JDK 物理分代时代 | | 年轻代 (YoungGen: Eden S0 S1) | 老年代 (OldGen) | | [Serial] [ParNew] [Parallel Scavenger] | [Serial Old] [CMS] [Parallel Old] | --------------------------------------------------------------------------------- | v --------------------------------------------------------------------------------- | JDK 逻辑分区 / 无分代时代 | | [G1 GC] : 划分为 2048 个等大 Region逻辑保留 Eden/Survivor/Tenured | | [ZGC] : 动态 Region (2MB/32MB/2MB*N)Colored Pointers Load Barriers | | [Shenandoah] : 读屏障/Brooks Pointers全阶段并发 GC | ---------------------------------------------------------------------------------下面是各大主力收集器的核心特性对比收集器线程模型核心目标适用堆内存范围JDK 版本状态吞吐量/延迟侧重Serial / Serial Old单线程极小资源消耗 512 MB 512\text{MB}512MB仍保留 (客户端模式)高吞吐 (仅单核)Parallel Scavenger/Old多线程并行最大化 CPU 利用率1 GB − 8 GB 1\text{GB} - 8\text{GB}1GB−8GBJDK 8 默认吞吐量优先CMS多线程并发降低停顿时间2 GB − 16 GB 2\text{GB} - 16\text{GB}2GB−16GBJDK 9 废弃, JDK 14 移除延迟优先G1 GC多线程并发可预测的停顿目标4 GB − 64 GB 4\text{GB} - 64\text{GB}4GB−64GBJDK 9 默认延迟/吞吐平衡ZGC多线程全并发 1 ms 1\text{ms}1ms极低停顿16 MB − 16 TB 16\text{MB} - 16\text{TB}16MB−16TBJDK 15 正式商用极低延迟优先 3. Serial 串行收集器单线程的特定场景价值Serial年轻代复制算法和 Serial Old老年代标记-整理算法是最古老的收集器。Client App: ------ [ User Thread Running ] ------ [ STW ] ------- [ User Thread Running ] | GC Thread: [ Single GC Thread ]Warning (生产坑点)绝对不要在生产环境的 4C8G 以上容器中指定-XX:UseSerialGC。单线程 GC 清理 8GB 堆内存时会导致数分钟的 STW。但 Serial 并没有死。在 Docker 容器化时代单核 CPU或 0.5 核 Sidecar 容器、内存限制在 250MB 左右的小型微服务或 Lambda 边缘函数中-XX:UseSerialGC依然是最佳选择因为它没有任何多线程上下文切换nvcswch的额外消耗垃圾回收器占用的额外内存Footprint极小。⚡ 4. Parallel并行收集器吞吐量优先的利器与代价Parallel Scavenger / Parallel Old 是 JDK 8 的默认组合。其核心逻辑是充分利用多核 CPU 的计算资源在 GC 时启动多个垃圾回收线程并行清理以缩短 STW 时间达到最大吞吐量Throughput。我们可以通过模拟触发 Parallel GC 的配置来观测其表现// VM Options: -XX:UseParallelGC -Xms512m -Xmx512m -XX:PrintGCDetailspublicclassParallelGCTest{publicstaticvoidmain(String[]args){Listbyte[]allocationListnewArrayList();for(inti0;i1000;i){// 每次分配 1MB 内存allocationList.add(newbyte[1024*1024]);try{Thread.sleep(10);}catch(InterruptedExceptione){Thread.currentThread().interrupt();}}}}控制台 GC 日志如下[GC(Allocation Failure)[PSYoungGen: 131072K-21504K(153088K)]131072K-103432K(502272K),0.0182410secs][Times:user0.06sys0.01,real0.02secs][Full GC(Ergonomics)[PSYoungGen: 21504K-0K(153088K)][ParOldGen: 81928K-102400K(349184K)]103432K-102400K(502272K),[Metaspace: 3120K-3120K(1056768K)],0.0892301secs][Times:user0.32sys0.00,real0.09secs]核心调优参数折中Trade-off-XX:GCTimeRatio99意味着允许垃圾回收时间占总运行时间的1 / ( 1 99 ) 1 % 1/(199) 1\%1/(199)1%。-XX:MaxGCPauseMillis200给 Parallel 设置停顿时间上限。但该参数存在反作用——为了满足停顿时间上限JVM 会自动缩小年轻代堆大小导致更频繁地触发 GC吞吐量反而大幅下降。 5. CMS与G1并发收集器低延迟演化与并发标记坑点 5.1 CMSConcurrent Mark Sweep碎片化与Concurrent Mode FailureCMS 是第一个实现了用户线程与垃圾收集线程并发执行的收集器针对老年代设计。1. 初始标记 (STW) -- 仅标记 GC Roots 直接相连的对象 (极快) 2. 并发标记 -- 开启并发标记线程沿 GC Roots 追踪对象图 (耗时长不 STW) 3. 重新标记 (STW) -- 修正并发标记期间因用户线程继续运行而导致标记变动的对象 (增量更新) 4. 并发清除 -- 清除已死对象 (与用户线程并发)Warning (线上踩坑)CMS 使用标记-清除Mark-Sweep算法必定产生大量的内存碎片。当老年代无法找到足够大的连续空间分配大对象时会触发严重的Concurrent Mode Failure强制退化为单线程 Serial Old 整理模式造成长达数秒甚至几十秒的 STW 灾难。解决方法是强制开启内存碎片整理-XX:UseCMSInitiatingOccupancyOnly-XX:CMSInitiatingOccupancyFraction70# 老年代达到 70% 即触发 CMS保留空间应对并发浮动垃圾-XX:UseCMSCompactAtFullCollection-XX:CMSFullGCsBeforeCompaction2# 2 次 Full GC 后做一次压缩整理 5.2 G1Garbage-FirstRegion化与停顿预测模型G1 彻底打破了传统的物理分代界限。它把整个 Java 堆划分为约 2048 个大小相等的独立Region1 MB − 32 MB 1\text{MB} - 32\text{MB}1MB−32MB必须是 2 的幂。------------ | E | S | O | E | E: Eden Region ------------ S: Survivor Region | H | O | E | O | O: Old Region ------------ H: Humongous Region (大对象空间, 0.5 Region) | O | S | H | E | ------------G1 的核心设计是可预测的停顿模型Pause Prediction Model。它使用衰减均值Decay Average算法实时统计每个 Region 的回收价值回收可释放的内存 vs 回收所消耗的时间优先回收价值最大的 RegionGarbage-First 的由来。并发标记核心SATBSnapshot-At-The-Beginning与写屏障在并发标记阶段为了解决用户线程与 GC 线程并发执行时漏标原本存活的对象被误删的问题G1 采用了SATB技术。// 逻辑上的写屏障伪代码模拟voidpre_write_barrier(oop*field_address){if(G1State::is_concurrent_mark_in_progress()){oop old_value*field_address;if(old_value!NULL){// 将旧引用压入 SATB 本地缓冲区保障并发标记开始时的对象图快照不被破坏enqueue_satb_buffer(old_value);}}}推荐的线上 G1 参数配置-XX:UseG1GC-XX:MaxGCPauseMillis200# 目标停顿时间默认 200ms-XX:InitiatingHeapOccupancyPercent45# 堆使用率达到 45% 时触发并发标记周期 (IHOP)-XX:G1HeapRegionSize16m# 显式指定 Region 大小-XX:G1ReservePercent10# 预留 10% 空间作为 Eden 到 Survivor 的缓冲区防止 Evacuation Failure⚡ 6. ZGC并发收集器10ms到1ms的着色指针革命从 OpenJDK 15 商用的ZGCZ Garbage Collector是真正意义上的“低延迟怪物”。在 16TB 的超大堆下能将 STW 停顿时间控制在1ms 以内。ZGC 实现了全阶段并发并发标记、并发预备重分配、并发重分配、并发重映射其核心黑科技在于着色指针Colored Pointers与读屏障Load Barriers。在 64 位机器上ZGC 将寻址指针的高几位借用来存放 GC 状态标记--------------------------------------------------------------- | 18 bits (Unused) | 4 bits (GC Metadata| 42 bits (Object Address| | | Marked0/Marked1/ | 支持 4TB/16TB 物理内存)| | | Remapped) | | ---------------------------------------------------------------// ZGC 读屏障的核心执行逻辑JIT 编译时植入oopzgc_load_barrier(oop*reference_address){oop bad_ref*reference_address;// 检查指针的 GC Metadata 标志位如果不是 Bad Color 则直接返回极快if(is_bad_color(bad_ref)){// 触发 slow_path如果对象正在被移动更新指针并返回新地址 (自愈指针)returnresolve_bad_color(reference_address);}returnbad_ref;}# JDK 17 / JDK 21 生产推荐配置java-XX:UseZGC-XX:ZGenerational-Xms32g-Xmx32g-XX:ReservedCodeCacheSize512m-jarapp.jar在 JDK 21 中ZGC 已经默认引入了分代 ZGCGenerational ZGC解决了旧版 ZGC 在高分配速率Allocation Rate下容易导致 Allocation Stall分配停顿的隐患。 7. JVM垃圾收集器必考点与调优指南总结在面试与线上故障排查中只需牢记以下硬核逻辑链条垃圾回收三要素STW 停顿时间、内存吞吐量、堆空间 Footprint。三者不可兼得调优本质上是对业务场景的Trade-off。三色标记与漏标解决黑色已标记且子节点已扫描、灰色自身已标记但子节点未扫描完、白色未标记。CMS 解决漏标增量更新Incremental Update破坏“黑色指向白色”条件通过写屏障记录新引用重新标记阶段 STW 扫描。G1 / ZGC 解决漏标原始快照SATB破坏“灰色断开白色”条件通过写屏障记录断开的引用将旧对象视作存活。ZGC 的核心突破利用着色指针 读屏障实现了对象的并发移动Relocation从而把转移阶段的 STW 降低到了近乎常数级别 1 ms 1\text{ms}1ms。生产选型极简规整 堆内存 4G Parallel GC (吞吐量优先) 或 G1 GC 堆内存 4G-64G G1 GC (平衡延迟与吞吐) 堆内存 64G / 低延迟 SLA 敏感情境 分代 ZGC (JDK 21)GC 调优不是调整几个-XX参数就能解决的灵丹妙药绝大多数 Full GC 告警本质上都是业务代码的大对象滥用、内存泄漏或长生命周期对象误晋升导致的。

相关新闻

2026/8/13 10:53:24

Vue 3 配置驱动式搜索组件封装:从 Schema 设计到高级功能实现

1. 项目缘起:为什么我们需要一个高度封装的搜索组件? 在后台管理系统、数据中台这类项目中,搜索功能几乎是每个列表页的标配。回想一下你最近参与的项目,是不是经常遇到这样的场景:产品经理拿着原型图过来,…

2026/8/13 11:48:28

AI LeetCode侧边栏:苏格拉底式提示如何提升算法思维

1. 先搞清楚这个工具到底解决什么问题,以及它和直接看答案的区别 看到“AI LeetCode side panel that gives Socratic hints, not solutions”这个标题,第一反应是:又一个AI刷题工具?但仔细看,它的核心是“苏格拉底式…

2026/8/13 11:48:28

VMWare虚拟机扩容全过程

* VMWare虚拟机扩容全过程 * ** 一、背景与用途: 作者在给JetsonOrinNano烧录系统配环境过程中发现商家配置好的虚拟机设置中划定了30GB内存,在SDKManager下载软件资源包过程中出现了爆满问题(其实我看一般30GB也够用,我勾选的…

2026/8/13 11:48:28

ComfyUI Manager完整指南:5分钟掌握AI工作流管理核心技术

ComfyUI Manager完整指南:5分钟掌握AI工作流管理核心技术 【免费下载链接】ComfyUI-Manager ComfyUI-Manager is an extension designed to enhance the usability of ComfyUI. It offers management functions to install, remove, disable, and enable various cu…

2026/8/13 11:48:28

MySQL索引失效的8种常见场景与优化实战

1. 索引失效的常见场景:从一次慢查询说起上周排查一个线上服务性能问题时,遇到一个典型的索引失效案例。一个看似简单的用户订单查询,在数据量增长到百万级后,响应时间从几十毫秒飙升到十几秒。SQL语句看起来没什么问题&#xff0…

2026/8/13 11:43:28

SecureCRT批量会话管理:从SSH2登录自动化到运维效率提升

1. 从单点登录到批量运维:一个被忽视的效率痛点 如果你是一名系统管理员、网络工程师,或者需要管理几十上百台服务器、网络设备的运维人员,那么对SecureCRT这款终端仿真软件一定不陌生。它的稳定、强大和丰富的协议支持(尤其是SSH…

2026/8/12 10:37:12

如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南 【免费下载链接】chinese_license_plate_generator 中国车牌生成器 项目地址: https://gitcode.com/gh_mirrors/ch/chinese_license_plate_generator 中国车牌生成器是一个基于Python的开源项目&#xff0c…

2026/8/12 5:35:25

当 LLM 遇见大文档:主流开源项目如何处理上下文超限

从 Agentic Loop 到 Repo Map,七种策略与六类陷阱引言:128K vs 10MB 的硬冲突 2026 年的 LLM 上下文窗口已达到 128K ~ 1M token(≈ 0.5MB ~ 4MB 文本),但 LLM 想要处理的真实数据规模远远超过这个量级:真实…

2026/8/13 0:02:21

Prefix Cache

Prefix Cache(前缀缓存) 是大模型推理引擎(如 vLLM、SGLang、TensorRT-LLM)中用于跨请求复用已计算 KV Cache 的核心内存与计算优化技术。 它的核心目的在于:彻底消除重复 Prompt 的 Prefill 阶段计算,将首…

2026/8/13 0:02:21

VSCode插件精选:从AI补全到代码规范,打造高效开发环境

1. 项目概述:为什么说插件是VSCode的灵魂?如果你和我一样,每天有超过8小时的时间是在VSCode里度过的,那你肯定明白,一个顺手的开发环境有多重要。VSCode本身已经足够优秀了,但真正让它从“好用的编辑器”蜕…

2026/8/13 0:02:21

如何快速完成文件批量重命名:FreeReNamer终极指南

如何快速完成文件批量重命名:FreeReNamer终极指南 【免费下载链接】FreeReNamer 功能强大又易用的文件批量重命名软件 项目地址: https://gitcode.com/gh_mirrors/fr/FreeReNamer 你是否曾经面对成百上千个杂乱无章的文件感到头疼?传统的手动重命…

2026/8/10 11:20:30

实测才敢推 AI论文网站 2026最新测评与推荐

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。一、综…

2026/8/11 17:06:59

2026必备!AI论文网站测评:最新推荐与深度对比

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。 一、…

2026/8/11 3:05:11

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

一天写完毕业论文在2026年已不再是天方夜谭。2026年最炸裂、实测能大幅提速的AI论文写作工具,覆盖选题构思、文献整理、内容生成、格式排版等核心场景,真正帮你高效搞定论文难题。 一、全流程王者:一站式搞定论文全链路(一天定稿首…