虚拟机回收算法怎么选?,JVM垃圾回收器对比指南

虚拟机回收算法没有银弹,核心是在吞吐量、停顿时间和内存占用之间做权衡;选型时先看应用场景是延迟敏感型还是吞吐优先型,再决定用分代、G1还是ZGC。

虚拟机回收算法有哪些:从分代到低延迟

基础回收算法:标记-清除、复制与标记-整理

JVM的垃圾回收算法演进,本质上是在解决三个问题:哪些内存可回收、怎么高效回收、怎么减少回收时的停顿,早期基础算法奠定了整个体系的基础。

JVM垃圾回收机制
加载中
JVM垃圾回收机制
B
BitlogicX
3.2万--
原视频地址
  • 标记-清除(Mark-Sweep):先遍历对象图标记存活对象,再统一清除未标记对象,该算法实现简单,但会产生大量内存碎片,后续分配大对象时容易触发频繁的Full GC。
  • 复制(Copying):把堆内存分成两块,只使用一块,GC时把存活对象复制到另一块,然后整块清空,内存分配效率高,不发生碎片,但可用内存空间被压缩一半,HotSpot虚拟机的新生代就采用这个思路,把Eden区与两个Survivor区按8:1:1比例划分。
  • 标记-整理(Mark-Compact):标记阶段与标记-清除一致,但后续将所有存活对象向内存一端移动,然后清理掉边界以外的内存,避免碎片,但移动对象会更新引用,增加停顿时间,老年代常用该算法或其变体。

现代垃圾回收器:CMS、G1、ZGC和Shenandoah

算法是理论,垃圾回收器是工程实现,各大JDK版本演变,催生了针对不同场景的回收器。

  • CMS(Concurrent Mark Sweep):主打低停顿,并发标记和并发清除,问题是并发模式失败时退化为Serial Old,且存在浮动垃圾和内存碎片,JDK 9开始被废弃,JDK 14正式移除。
  • G1(Garbage First):把堆划分为多个Region区域,维护优先列表,优先回收价值最大的Region,在可控停顿时间内尽可能提高吞吐量,兼顾延迟和吞吐,成为JDK 11之后服务端默认垃圾回收器。
  • ZGC(Z Garbage Collector):基于Region内存布局,染色指针和读屏障实现几乎全部的并发,停顿时间不随堆大小增长而增长,JDK 15进入正式版本。
  • Shenandoah:与ZGC目标类似,JDK 12引入,采用转发指针和碰撞指针,后续版本不断优化,适配需要低延迟的应用。

g1和zgc怎么选:延迟与吞吐的权衡

这是现阶段最常被问到的对比,毕竟从JDK 17到JDK 21,G1和ZGC是最主流的两个选择。

从延迟上看,ZGC的设计目标是尽量把停顿压制在10毫秒以内,甚至更短,G1的停顿预测模型依赖历史数据,默认目标为200毫秒,实际调优后可降到50毫秒左右,但堆越大、对象分配越快,越难保证稳定低延迟。

虚拟机回收算法怎么选?,JVM垃圾回收器对比指南

从吞吐量上看,G1在多数业务场景下更占优势,ZGC引入了染色指针等额外开销,读屏障和并发处理会占用一定CPU资源,如果应用对停顿不敏感,且追求更高CPU利用率,G1往往比ZGC表现更好。

从堆大小与JDK版本看,堆小于4GB时可以优先考虑G1,堆大于16GB且对停顿敏感时,ZGC是更合适的选择,JDK 21中ZGC还支持了分代模式,进一步缩小了与G1在吞吐量上的差距。

选择建议如下:

  • 交易系统、实时推荐、游戏服务端等要求毫秒级响应的场景,选ZGC或Shenandoah。
  • 数据处理、离线任务、Web应用等追求高吞吐且能容忍秒级停顿的场景,G1仍是稳妥之选。
  • 小堆内存且无需复杂调优的场景,可以用JDK默认的G1加上-Xmx和-Xms启动参数,先跑起来再观察日志。

如何选择适合场景的回收策略:三步定位法

面对五花八门的算法和回收器,直接背参数没有意义,建议用下面的思路落地。

第一步:明确业务容忍的停顿标准

跟业务方确认两个问题:单次GC最长能接受多久?一分钟内能接受几次Full GC?如果答案是不能超过50毫秒且不允许Full GC,那么CMS就已经出局,G1需要精细调优,ZGC几乎不需要干预,如果业务是跑批任务,凌晨执行,一次Full GC停顿十几秒也无所谓,那G1甚至Parallel GC都完全够用。

第二步:观察当前GC日志与内存变化

在测试环境或灰度环境,用以下参数打印GC日志:

-Xlog:gc:file=gc.log:time,uptime,level,tags

多跑一段时间,观察Young GC的频率、平均停顿和Full GC的次数,如果新生代每次GC后存活对象比例波动大,说明对象生命周期不稳定;如果老年代持续增长且Full GC频繁,说明堆配置或回收器选择不合理。

进一步配合jstat -gcutil和jmap -histo查看各代占用和对象分布,这些是JDK自带的工具,不需要额外安装,操作路径为:启动应用后,在命令行直接执行jstat -gcutil <pid> 1000 10,每1秒采样一次,共采样10次。

第三步:根据场景特征确定回收策略

行业共识认为,没有最好只有最合适的回收器,判断依据可从以下维度展开。

  • 对象存活率:新生代存活率低(小于10%)时,复制算法的效率极高,存活率超过50%时,复制算法会频繁把对象拷来拷去,不如标记-整理实在。
  • CPU核心数:ZGC和Shenandoah需要较多CPU线程做并发标记和并发清理,如果服务器只有2核4线程,G1更省心,ZGC的CPU消耗可能挤占业务线程资源。
  • 虚拟机回收算法怎么选?,JVM垃圾回收器对比指南

  • 堆内存大小:大堆(几十GB甚至上百GB)遇到G1容易因并发标记周期长带来较长的停顿,ZGC在超大堆上的优势更明显。
  • JDK版本与生态:老项目还在JDK 8上,只能选G1或CMS,ZGC根本没法用,新项目直接奔JDK 17,老老实实用G1起步,等真的遇到长停顿再切ZGC也不迟。

分代回收机制:新生代、老年代与元空间

不管选哪种回收器,理解分代模型能让调优更有章法。

新生代与老年代的回收路径

对象优先在Eden区分配,Eden区填满触发Minor GC,存活对象进入Survivor区,经历一定次数的Minor GC后,年龄达到阈值(默认15)的对象晋升到老年代,大对象直接进入老年代,避免在Eden和Survivor之间反复复制。

老年代空间不足时触发Major GC/Full GC,此时回收的代价远高于Minor GC,G1和ZGC都试图减少Full GC的发生,特别是ZGC,几乎不触发Full GC。

元空间与内存泄漏排查

JDK 8之后永久代被移除,改为元空间,元空间使用本地内存,触发回收的条件是类加载器及其加载的类无引用,频繁动态生成类的框架(如Spring、CGLIB)若使用不当,容易导致元空间溢出,排查时用jcmd <pid> GC.class_stats查看类统计信息。

以下表格对比主流回收器的核心维度,方便快速筛选:

回收器 适用的JDK版本 暂停目标 吞吐量 典型场景
Parallel GC JDK 8及以后 高 很高 批量计算、后台任务
G1 JDK 8u40+ 可控 较高 通用服务端应用
ZGC JDK 15+ 极低 中等 大堆、低延迟场景
Shenandoah JDK 12+ 极低 中等 与ZGC类似,但实现不同

低延迟场景的回收策略实践

延迟敏感型应用怎么调

如果应用是K线行情推送或在线支付,核心诉求就是平均GC停顿在10毫秒以下,先把堆内存固定起来,-Xms和-Xmx设成相同值,避免扩容时触发Full GC,然后使用ZGC,加参数-XX:+UseZGC,再配套-XX:ConcGCThreads控制并发GC线程数,通常设置为CPU核数的四分之一到三分之一。

调完后,用线上流量压测观察P99延迟,如果延迟曲线在GC周期后出现尖刺,说明ZGC的并发周期与业务高峰重叠,可以错开GC时间或调大预留内存。

虚拟机回收算法怎么选?,JVM垃圾回收器对比指南

吞吐优先型应用怎么调

类似离线报表、数据清洗程序,跑得越快越好,直接使用Parallel GC,参数为-XX:+UseParallelGC,再设置-XX:ParallelGCThreads为CPU物理核数,同时适当增大新生代比例,比如-XX:NewRatio=1,让更多对象在新生代就消亡,减少晋升。

如果遇到老年代经常满了但堆内存还有不少空闲的情况,检查是否有大数组或缓存长期持有对象引用,这时候调GC参数不如修代码。

常见调优误区

  • 盲目追求低延迟,给4G堆的应用强行上ZGC,可能比G1更慢。
  • 堆内存设得越大越好,实际上超过物理内存会导致频繁的swap,反而拖垮性能。
  • 忽略GC日志的保留时间,日志量很大但没留足够天数的历史,排障时无从下手。

聊聊R语言环境下的回收机制 (相关衍生话题)

不少统计建模或数据分析的朋友会问,R语言的GC是不是和Java一样,R语言采用一种简单的分代GC,主要使用标记-清除策略,并引入写屏障管理写入屏障,R中的gc()函数能强制触发GC,但多数情况下不需要手动干预,如果做大内存的向量计算,R的GC效率不如JVM的并发收集器,这也是R生态处理超大数据集不如Java高效的原因之一,至于R和Java的回收算法对比,可以简单理解为R重视简单可靠,Java重视可调优和低延迟。

Q&A:虚拟机回收算法常见疑问

为什么Full GC之后老年代内存还是缓慢增长?

可能是某个缓存对象始终被强引用,GC无法回收,用jmap -dump:format=b,file=heap.hprof <pid>导出堆快照,再用MAT或VisualVM分析,重点关注大对象和线程栈中的局部变量引用。

用了G1之后,还需要手动设置SurvivorRatio吗?

G1的Survivor区大小是动态调整的,手动设置-XX:SurvivorRatio效果不稳定,建议直接依赖G1的自适应逻辑,只关注-XX:G1NewSizePercent和-XX:G1MaxNewSizePercent这两个参数来控制新生代占比。

生产环境从CMS切换到G1或ZGC,需要改动代码吗?

不需要改业务代码,但需重新验证GC参数和监控指标,CMS的一些参数在G1或ZGC下不生效,比如-XX:CMSInitiatingOccupancyFraction,切换前把旧参数清理干净,重新参考新回收器的推荐配置,并在压测环境跑一轮完整的排查。

垃圾回收没有万能答案,理解每种算法的取舍,再结合业务停顿标准和硬件资源做出选择,就能让JVM在绝大多数场景下安静工作,先跑起来采集日志,用数据驱动选型,比上来就堆参数更可靠。

首发原创文章,作者:王坚‌,如若转载,请注明出处:https://idctop.com/article/614355.html

赞 (0)
白云一键重装系统好用吗,小白操作会不会出问题?
上一篇 2026年9月1日 10:55
怎样把图片制作成视频?新手能快速学会吗,图片转视频用什么软件
下一篇 2026年9月1日 10:57

相关推荐

  • 百万人级服务器有哪些?哪些配置最实用?

    百万人级服务器不是某一台“超级服务器”,而是一套由接入层、计算层、数据层、存储层和运维体系组成的大规模集群,常见选型包括裸金属、云服务器、Kubernetes节点、GPU服务器、分布式数据库、Redis Cluster、Kafka以及CDN边缘节点,百万人级服务器有哪些?先按角色拆开看把“百万人级”理解成同时在……

    2026年10月7日
    100
  • html5开发网站实例怎么做?html5开发网站实例教程

    © 2026 版权所有“`HTML5开发网站实例中的多媒体与交互HTML5最引人注目的特性之一是其对多媒体内容的原生支持,在HTML5之前,播放视频或音频需要依赖第三方插件如Flash或QuickTime,这不仅增加了加载负担,还存在安全隐患,和标签让开发者能够轻松嵌入媒体文件,响应式媒体嵌入策略为……

    2026年6月10日
    3200
  • 华为企业业务如何加速行业智能化,行业智能化转型有哪些关键?

    华为企业业务正通过“技术扎根、生态共建、场景驱动”三线并进的方式,把AI从单点工具升级为重塑生产力的核心引擎,加速千行百业的智能化进程,这套打法不靠单一产品取胜,而是以昇腾AI算力底座、盘古大模型和行业伙伴生态为支点,解决企业“不会转、不敢转、转不动”的深层痛点,华为行业智能化解决方案到底改变了什么过去两年,行……

    2026年9月1日
    400
  • Weebly页面打开为何是空白?Weebly网站显示空白怎么解决

    Weebly页面显示空白通常由浏览器缓存冲突、浏览器扩展程序干扰或服务器端代码加载失败引起,清除缓存、禁用插件及检查网络连接是解决此问题的首要步骤,面对Weebly网站突然变成一片白屏的情况,很多站长都会感到焦虑,毕竟这直接关系到访客体验和业务转化,这种问题在业内专家指出中,往往不是单一原因造成的,而是前端加载……

    2026年6月22日
    3200
  • 互联网区块链分布式身份服务发布是什么?区块链分布式身份服务有哪些

    互联网区块链分布式身份服务(DID)的发布标志着数字身份从“平台托管”向“用户自主掌控”的根本性转变,其核心价值在于通过去中心化技术实现数据隐私保护与跨平台互认,彻底解决传统账号体系下的数据泄露与垄断痛点,过去十年,我们在互联网上的每一次点击、每一笔交易、每一条社交动态,都存储在大型科技公司的服务器上,这种中心……

    2026年6月2日
    4500
  • html中怎么写asp代码?asp.net与html混合开发

    “`在这个例子中:静态部分:、、等标签原样输出,动态部分:内的代码在服务器端执行,Response.Write将当前时间写入输出流,替换掉代码块的位置,变量与输出ASP中常用的输出方式是<%= %>,它是Response.Write的简写形式,写法1:写法2:写法2更简洁,常用于在HTML标签属性……

    2026年6月7日
    3100
  • TypeScript编译器怎么安装?TypeScript安装教程

    TypeScript编译器安装的核心答案是通过npm全局安装TypeScript包,执行npm install -g typescript即可在任意项目中直接使用tsc命令进行编译,这是目前最主流且稳定的安装方式,在2026年的前端开发生态中,TypeScript依然是构建大型应用的首选语言,许多开发者在初次接……

    2026年6月22日
    2110
  • 如何在Ubuntu服务器安装配置Jitsi Meet?Ubuntu部署Jitsi Meet详细步骤

    在Ubuntu服务器上部署Jitsi Meet是构建私有化视频会议系统的最佳方案,它免费开源、无需注册即可使用,且通过Docker或官方脚本可实现一键式快速部署,对于企业IT管理员或技术爱好者而言,搭建一个安全、可控的视频会议平台往往比购买SaaS服务更具吸引力,Jitsi Meet凭借其开源特性,成为了许多团……

    2026年6月22日
    1700
  • 广州100g高防dns解析租用价格多少钱?100g高防dns解析租用哪里好

    在广州地区部署高防DNS解析服务,选择100G防御带宽是目前企业保障业务连续性的最佳性价比方案,能够有效抵御大规模DDoS攻击,确保域名解析的稳定与快速,核心结论在于:通过租用专业的广州100G高防DNS解析服务,企业无需自建昂贵的清洗中心,即可获得电信级的防护能力,实现秒级故障切换与智能解析调度,这是应对当下……

    2026年4月1日
    9100
  • ch域名是哪个国家?ch域名注册价格及申请流程详解

    CH域名属于瑞士国家顶级域名(ccTLD),其注册价格通常在每年100元至300元人民币之间,具体费用取决于注册商及是否包含隐私保护服务,适合希望建立瑞士品牌形象或针对欧洲市场业务的企业使用,在国际化域名布局中,很多人容易将CH域名与常见的CN、US等混淆,CH作为瑞士的官方国家代码,不仅代表着一个高度发达的经……

    2026年6月18日
    6100

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注