垃圾收集器有哪些?Serial、ParNew、CMS、G1、ZGC详解
编程并不是一个机械性的工作,而是需要有思考,有创新的工作,语法是固定的,但解决问题的思路则是依靠人的思维,这就需要我们坚持学习和更新自己的知识。今天golang学习网就整理分享《垃圾收集器有哪些?Serial、ParNew、CMS、G1、ZGC全解析》,文章讲解的知识点主要包括,如果你对文章方面的知识点感兴趣,就不要错过golang学习网,在这可以对大家的知识积累有所帮助,助力开发能力的提升。
答案:Java垃圾收集器根据应用场景选择,Serial单线程适合小内存,ParNew配合CMS降低停顿,CMS追求低延迟但有碎片问题,G1兼顾吞吐与延迟,ZGC实现毫秒级停顿支持大堆,选择时需权衡延迟、吞吐、堆大小及JDK版本,并通过GC日志分析优化。
Java的垃圾收集器,说白了,就是JVM里负责回收不再使用的内存空间的“清洁工”。我们常用的主要有Serial、ParNew、CMS、G1,以及更现代的ZGC。它们各有特点,有的追求极致吞吐量,有的侧重低停顿,选择哪个,往往取决于你的应用场景和对性能的具体要求。
解决方案
在我看来,理解这些垃圾收集器,就像是了解不同类型的引擎,每款都有其设计哲学和适用领域。
Serial收集器 Serial,顾名思义,就是单线程的。它在进行垃圾收集时,会暂停所有用户线程(也就是我们常说的“Stop-The-World”,简称STW),直到垃圾收集完成。新生代采用复制算法,老年代采用标记-整理算法。它的优点是简单、高效,因为没有线程切换的开销。在单核CPU或者堆内存很小的客户端应用中,Serial GC的表现其实不赖。但对于服务器端应用,尤其是在多核处理器普及的今天,它的STW时间往往是不可接受的,想象一下你的服务突然卡住几百毫秒甚至几秒,那体验可太糟糕了。我个人觉得,它更多是作为一种“教学模型”和某些特定小场景下的备选。
ParNew收集器 ParNew是Serial的多线程版本,它在新生代使用多线程进行垃圾收集,同样会触发STW。老年代通常与CMS配合使用。既然是多线程,在多核CPU环境下,它的STW时间会比Serial短很多。它出现的意义,很大程度上是为了配合CMS,因为CMS在新生代无法独立完成收集工作,需要一个多线程的收集器来搭档。所以,你很少会单独配置ParNew,它几乎总是和CMS一起出现。
CMS(Concurrent Mark Sweep)收集器 CMS,并发标记清除,是HotSpot虚拟机中第一款真正意义上的并发收集器。它的目标是获取最短的停顿时间,所以它在收集的大部分时间里,都可以和用户线程一起工作。它主要分为四个阶段:
- 初始标记(Initial Mark):STW,但时间很短,标记GC Roots能直接关联到的对象。
- 并发标记(Concurrent Mark):与用户线程并发执行,遍历所有可达对象。
- 重新标记(Remark):STW,修正并发标记期间因用户程序运行导致的对象引用变动。这个阶段通常比初始标记长,但比新生代GC短。
- 并发清除(Concurrent Sweep):与用户线程并发执行,清除已标记的垃圾。 CMS的优点显而易见:低停顿。但它也有几个让我头疼的地方:
- 对CPU资源敏感:并发阶段会占用一部分CPU资源,影响应用吞吐量。
- 无法处理“浮动垃圾”:在并发清除阶段产生的垃圾,只能留到下一次GC再处理。
- 空间碎片问题:标记-清除算法的通病,会产生大量不连续的内存碎片,当碎片过多时,可能会提前触发Full GC,而Full GC时,CMS会退化成Serial GC,导致长时间STW。
- 并发失败(Concurrent Mode Failure):如果在并发清除过程中,预留的内存不足以支撑用户程序运行,就会触发Full GC。
我曾经在一些老项目中遇到过CMS的碎片问题,那真是让人抓狂,服务隔一段时间就卡顿一下,排查起来很费劲。
G1(Garbage-First)收集器 G1是JDK 7u4版本开始提供,并在JDK 9之后成为默认的垃圾收集器。它在设计上就考虑到了大堆内存和可预测的停顿时间。G1将Java堆划分为多个大小相等的Region(区域),每个Region可以扮演新生代、老年代,甚至是巨型对象区域。它的工作原理是:
- 全局并发标记:与CMS类似,进行并发标记。
- 停顿预测模型:这是G1的核心,它会维护每个Region的垃圾回收价值(回收所需时间、能回收多少空间),然后根据用户设定的停顿时间目标(
MaxGCPauseMillis
),优先回收那些垃圾最多、回收效率最高的Region。 G1的优点在于:
- 可预测的停顿时间:通过Region的划分和停顿预测模型,可以尽可能地满足用户设定的停顿时间目标。
- 避免碎片:G1在回收Region时,采用的是复制算法或标记-整理算法,所以不会产生内存碎片。
- 兼顾吞吐量和延迟:在平衡这两者上做得很好。 对我而言,G1是目前最“省心”的收集器之一,尤其是在处理几十GB甚至上百GB堆内存的应用时,它的表现非常稳健。
ZGC ZGC是JDK 11引入的,旨在实现极低的停顿时间(通常在10ms以内,甚至1ms左右),并且停顿时间不随堆内存大小而变化。它的设计目标是支持TB级别的堆内存。ZGC的核心技术包括:
- 着色指针(Colored Pointers):将一些元数据信息直接存储在对象指针中,减少查找时间。
- 读屏障(Read Barrier):在对象读取时插入屏障,保证并发收集的正确性。
- Region管理:与G1类似,也是基于Region的。 ZGC几乎所有的工作都是并发进行的,包括标记、重定位等。这使得它的STW时间极短。 它的优点显而易见:超低停顿,支持超大堆。但缺点是:
- 对硬件要求高:需要64位操作系统。
- 吞吐量可能略低于G1:因为读屏障会有一些开销。
- JDK版本要求高:目前仅在JDK 11及更高版本中可用。 我个人对ZGC充满期待,在对延迟要求极其苛刻的场景,比如金融交易系统、实时大数据处理,ZGC简直是“神兵利器”。但对于一般的Web应用,G1可能已经足够好。
如何根据应用特性选择合适的垃圾收集器?
选择垃圾收集器,从来都不是一道简单的选择题,它更像是一场对应用需求和JVM机制的深度博弈。我的经验是,没有“最好”的收集器,只有“最适合”你应用的。
关注你的核心指标:
- 吞吐量(Throughput)优先? 如果你的应用是批处理、数据分析等,可以接受较长的停顿,但希望在单位时间内处理更多任务,那么Parallel GC(不是本文讨论的重点,但它就是高吞吐量代表)或者G1在某些配置下会是好的选择。
- 延迟(Latency)优先? 如果你的应用是Web服务、实时交易系统、GUI应用,对响应时间非常敏感,那么CMS、G1或者ZGC是你的首选。
- 堆内存大小:
- 小堆(几百MB到1GB):Serial GC或Parallel GC可能表现不错,甚至G1在这种情况下也可能有点“杀鸡用牛刀”。
- 中等堆(1GB到4GB):G1通常是个不错的通用选择。CMS也可以考虑,但要警惕碎片问题。
- 大堆(4GB到几十GB甚至TB):G1是目前最稳妥的选择。如果对停顿要求极高,ZGC(JDK 11+)或Shenandoah(JDK 12+)则能提供更极致的体验。
考虑JDK版本:
- JDK 8及以前:G1是可选的,但默认可能不是。CMS是低延迟的代表。
- JDK 9及以后:G1成为默认GC。ZGC和Shenandoah等新一代收集器也逐渐成熟。新版本通常意味着对GC的优化和新特性。
CPU核数:
- 单核或双核:Serial GC或ParNew在小堆下可能还行。但多核是主流,多线程GC的优势明显。
- 多核:ParNew、CMS、G1、ZGC都能很好地利用多核并行处理能力。
实际测试与观察: 这可能是最重要的一点。理论分析是基础,但实际应用的负载、数据模式、对象生命周期都会影响GC表现。我的建议是:
- 从默认GC开始,或者根据上述原则选一个初步的GC。
- 在生产环境或类生产环境进行压力测试。
- 务必收集GC日志(
-Xlog:gc*
或-XX:+PrintGCDetails -XX:+PrintGCDateStamps
等)。 - 使用GCViewer、JConsole、VisualVM等工具分析GC日志,观察停顿时间、GC频率、内存使用情况。
- 根据分析结果,逐步调整JVM参数,比如新生代和老年代的比例、最大停顿时间目标等。
举个例子,如果我有一个电商后台服务,对响应时间有一定要求,同时堆内存可能在8GB左右,我会毫不犹豫地选择G1。如果这是一个实时金融风控系统,对毫秒级的延迟都不能容忍,并且堆内存可能达到几十GB,那么ZGC会是我的重点考察对象。
垃圾收集器调优有哪些常见误区和最佳实践?
GC调优,很多人一上来就想改参数,但往往忽略了更本质的问题。我见过太多因为不当调优导致性能更差的案例。
常见误区:
- 盲目追求低延迟:为了追求极致的低停顿,不惜牺牲吞吐量。结果是GC虽然快了,但应用处理请求的能力下降,整体性能反而变差。要知道,GC的本质是内存管理,吞吐量和延迟往往是此消彼长的关系。
- 过度配置GC参数:JVM提供了大量的GC参数,但不是每个参数都需要你动。很多参数是相互关联的,改一个可能影响多个地方。不理解参数含义就随意修改,往往会适得其反。
- 不看GC日志就调优:没有数据支撑的调优都是“玄学”。GC日志是了解JVM内存行为的唯一窗口,不分析日志就直接改参数,就像闭着眼睛开车。
- 将GC问题归咎于JVM:很多时候,频繁的Full GC或者内存溢出(OOM)并非GC本身的问题,而是应用代码存在内存泄漏、对象创建过于频繁、对象生命周期过长等问题。GC只是个“背锅侠”。
- 过早优化:在应用上线前,或者在没有明确性能瓶颈的情况下,就花费大量时间进行GC调优,这是一种资源浪费。
最佳实践:
基准测试和GC日志分析先行:
- 首先,确保你的应用在稳定、有代表性的负载下运行。
- 启用详细的GC日志:
-Xlog:gc*
(JDK 9+)或-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/path/to/gc.log
(JDK 8)。 - 使用GCViewer、GCEasy等工具分析日志,关注以下指标:
- GC停顿时间(Pause Time):单次停顿最长时间、平均停顿时间。
- GC频率:Young GC、Old GC(Full GC)的发生频率。
- 内存使用情况:GC前后堆内存的变化,是否存在内存泄漏趋势。
- 晋升老年代的对象大小和频率。
- 找出GC瓶颈所在,是Young GC频繁导致停顿,还是Full GC导致长时间停顿。
从默认设置开始,逐步调整:
- JVM的默认GC设置通常对大部分应用都有不错的通用性。
- 如果需要调优,从最关键的参数开始:
- 堆内存大小:
-Xms
,通常设置成一样,避免运行时动态调整。-Xmx - 新生代大小:
-Xmn
或-XX:NewRatio=
。新生代太小容易频繁Young GC,太大可能导致老年代空间不足或Young GC停顿时间过长。 - G1的最大停顿时间目标:
-XX:MaxGCPauseMillis=
。 - CMS的并发GC触发阈值:
-XX:CMSInitiatingOccupancyFraction=
。
- 堆内存大小:
- 每次只调整少量参数,观察效果,避免“一次性大改”。
关注代码层面的优化:
- 避免内存泄漏:例如,静态集合持有对象引用不释放、资源未关闭等。
- 减少对象创建:尽量复用对象,减少临时对象的产生。使用对象池、享元模式等。
- 合理使用数据结构:选择适合场景的数据结构,避免不必要的内存开销。
- 避免大对象直接进入老年代:这会增加老年代GC的压力。
理解晋升老年代的机制:
- 对象在新生代经历多次Young GC仍存活,会晋升到老年代。
- 大对象会直接进入老年代。
- 新生代空间分配担保失败也会导致对象提前进入老年代。
- 理解这些机制,有助于你调整新生代大小,减少老年代压力。
GC调优不是一蹴而就的,它是一个持续的、迭代的过程。关键在于“观察-分析-调整-验证”的循环。
为什么说理解垃圾收集器的工作原理对Java开发者至关重要?
作为一名Java开发者,如果对垃圾收集器一无所知,那就像是开着一辆高性能跑车,却不知道引擎盖下面藏着什么,更别提如何保养和维修了。理解GC的工作原理,在我看来,是提升你技术深度和解决实际问题能力的关键一环。
排查和解决性能瓶颈: 当你的应用出现卡顿、响应缓慢,或者CPU使用率飙高时,GC问题往往是首要排查对象之一。频繁的Full GC、长时间的STW,都可能导致服务不可用。如果你理解GC的原理,就能快速定位是新生代GC问题还是老年代GC问题,进而分析是内存泄漏、对象分配过快,还是GC配置不当。否则,你可能只能束手无策,或者盲目重启服务。
优化内存使用和应用设计: 理解GC会让你在编写代码时,自然而然地思考对象的生命周期、内存分配模式。你会更倾向于复用对象、减少临时对象的创建、避免不必要的内存占用。例如,如果你知道G1是分Region的,你可能会在设计时避免创建超大对象,以免它们直接进入老年代或巨型对象区,影响GC效率。这种“内存友好型”的编程习惯,能从根本上提升应用的健壮性和性能。
预测和避免内存溢出(OOM): OOM是Java应用中最常见的运行时错误之一。理解GC如何回收内存、内存分配失败的场景,能帮助你更好地预测何时可能发生OOM,并提前采取措施。例如,通过监控JVM的内存使用趋势,结合GC日志,你可以在内存耗尽前发现问题,而不是等到服务崩溃。
提升你的技术栈深度和面试竞争力: GC是JVM的核心组成部分,也是Java高级工程师面试中必考的知识点。对GC的深入理解,不仅能让你在面试中脱颖而出,更能证明你对Java生态系统有全面的把握,而不仅仅停留在API层面。这代表着你能够处理更复杂、更底层的技术挑战。
更好地理解和利用JVM的特性: JVM是一个复杂的运行时环境,GC只是其中一环。但GC的运作方式,与类加载、线程管理、即时编译等都有千丝万缕的联系。理解GC,能让你对整个JVM的运行机制有更深刻的认识,从而更好地利用JVM提供的各种特性和工具。
说白了,GC不是一个“黑盒”,它是一套精密的内存管理系统。作为开发者,我们有责任去了解它,驾驭它,让我们的应用跑得更快、更稳定。这不仅仅是技术上的挑战,更是我们对代码、对系统负责任的一种体现。
理论要掌握,实操不能落!以上关于《垃圾收集器有哪些?Serial、ParNew、CMS、G1、ZGC详解》的详细介绍,大家都掌握了吧!如果想要继续提升自己的能力,那么就来关注golang学习网公众号吧!

- 上一篇
- AO3官网2025最新入口地址公布

- 下一篇
- WooCommerce如何显示特色产品标签
-
- 文章 · java教程 | 55秒前 |
- LinkedHashMap的使用详解与示例
- 279浏览 收藏
-
- 文章 · java教程 | 33分钟前 | 初始化 空指针异常 nullpointerexception Optional类 Objects.requireNonNull
- Java空指针异常解决方法
- 306浏览 收藏
-
- 文章 · java教程 | 37分钟前 |
- Java序列化漏洞深度解析
- 395浏览 收藏
-
- 文章 · java教程 | 48分钟前 |
- JavaApplet兼容方案及使用教程
- 440浏览 收藏
-
- 文章 · java教程 | 51分钟前 |
- Java多版本切换与配置方法详解
- 342浏览 收藏
-
- 文章 · java教程 | 1小时前 |
- JavaSSLSocket与TLS安全通信详解
- 294浏览 收藏
-
- 文章 · java教程 | 1小时前 | keystore TrustManager JavaSSL验证 跳过SSL验证 自定义SSL信任策略
- Java绕过SSL验证的实用方法
- 295浏览 收藏
-
- 文章 · java教程 | 1小时前 |
- Kafka与数据库事务一致性解决方案
- 311浏览 收藏
-
- 文章 · java教程 | 1小时前 |
- Java商品库存管理实现全解析
- 102浏览 收藏
-
- 文章 · java教程 | 2小时前 |
- Java集成百度语音SDK实现语音识别教程
- 428浏览 收藏
-
- 文章 · java教程 | 3小时前 |
- Java字符串海明距离计算方法详解
- 130浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 499次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 484次学习
-
- PandaWiki开源知识库
- PandaWiki是一款AI大模型驱动的开源知识库搭建系统,助您快速构建产品/技术文档、FAQ、博客。提供AI创作、问答、搜索能力,支持富文本编辑、多格式导出,并可轻松集成与多来源内容导入。
- 461次使用
-
- AI Mermaid流程图
- SEO AI Mermaid 流程图工具:基于 Mermaid 语法,AI 辅助,自然语言生成流程图,提升可视化创作效率,适用于开发者、产品经理、教育工作者。
- 1241次使用
-
- 搜获客【笔记生成器】
- 搜获客笔记生成器,国内首个聚焦小红书医美垂类的AI文案工具。1500万爆款文案库,行业专属算法,助您高效创作合规、引流的医美笔记,提升运营效率,引爆小红书流量!
- 1277次使用
-
- iTerms
- iTerms是一款专业的一站式法律AI工作台,提供AI合同审查、AI合同起草及AI法律问答服务。通过智能问答、深度思考与联网检索,助您高效检索法律法规与司法判例,告别传统模板,实现合同一键起草与在线编辑,大幅提升法律事务处理效率。
- 1273次使用
-
- TokenPony
- TokenPony是讯盟科技旗下的AI大模型聚合API平台。通过统一接口接入DeepSeek、Kimi、Qwen等主流模型,支持1024K超长上下文,实现零配置、免部署、极速响应与高性价比的AI应用开发,助力专业用户轻松构建智能服务。
- 1346次使用
-
- 提升Java功能开发效率的有力工具:微服务架构
- 2023-10-06 501浏览
-
- 掌握Java海康SDK二次开发的必备技巧
- 2023-10-01 501浏览
-
- 如何使用java实现桶排序算法
- 2023-10-03 501浏览
-
- Java开发实战经验:如何优化开发逻辑
- 2023-10-31 501浏览
-
- 如何使用Java中的Math.max()方法比较两个数的大小?
- 2023-11-18 501浏览