ICP备案

备案站点的垃圾回收停顿与 GC 调优运维

作者:备案源头内容团队内容审核:备案源头内容团队更新于 2026年10月3日

P99 曲线上周期性冒出的尖刺,和业务逻辑完全无关

一类让人格外头疼的延迟问题是这样的:接口平时响应很稳定,但每隔一段时间,总有少数请求的耗时突然飙升几百毫秒甚至更多,业务代码查了一遍又一遍,下游依赖也排查了一遍又一遍,就是找不到根因。真正的原因往往藏在一个和业务逻辑完全平行、自动运行、不受应用代码直接控制的过程里——垃圾回收。垃圾回收在清理内存的某些阶段需要暂停应用线程(Stop-The-World,STW),这段暂停时间会原样体现在请求耗时上,而且它的触发时机和业务请求的到达时机毫无关系,这正是它难以定位的根本原因。

关键要点

  • STW 停顿时长和堆的规模是正相关的,简单粗暴地调大堆来"减少 GC 次数"往往会把单次停顿拖得更长,是一种此消彼长的交易而非免费的优化。
  • 不同的垃圾回收算法在吞吐量和停顿延迟之间做了不同的取舍,选错回收器会让系统长期带着不必要的延迟尖刺运行。
  • 频繁的大对象分配会绕过常规的内存分配路径,直接加重老年代的回收压力,是很多"莫名其妙的 GC 频繁"背后的真实原因。
  • 调优之前必须先把问题量化清楚,凭感觉调整参数的后果通常是在一个方向上过度优化、牺牲了另一个本来还可以接受的指标。

STW 停顿和堆大小:此消彼长,不是免费的优化

垂直直觉上,"堆设得越大,能装的数据越多,GC 次数越少,性能应该越好"。但这个直觉只说对了一半:堆越大,意味着一旦触发需要扫描整个堆或者整理大片内存的回收动作,这次停顿需要处理的内存量也越大,单次停顿时长会相应拉长。

堆大小方向 GC 触发频率 单次停顿时长
偏小 更频繁触发 单次停顿较短
偏大 触发频率降低 单次停顿可能明显拉长

这意味着堆大小的调整本质上是在"频繁的小停顿"和"偶尔的大停顿"之间做权衡,不存在一个只调大堆就能让两者同时变好的方向。对延迟敏感的在线服务,往往宁可接受稍微频繁一点的小停顿,也不希望偶尔出现一次拖垮 P99 的大停顿;而对吞吐优先、延迟不敏感的批处理类任务,情况可能恰恰相反。判断该往哪个方向调,前提是先弄清楚业务对延迟和吞吐各自的容忍度,而不是照抄网上一个通用的堆大小配置。

不同回收算法:吞吐和延迟的取舍方向完全不同

主流的垃圾回收算法在设计目标上就存在明显分野,运维需要清楚自己的服务更看重哪一边:

回收器设计方向 核心目标 代价
吞吐优先型 单位时间内处理更多业务请求的总量,GC 本身的开销占比更低 停顿时间可能较长且不够可控
低延迟优先型 把单次停顿压缩到尽可能短,哪怕为此付出额外的并发开销 回收过程本身消耗更多 CPU,整体吞吐可能下降

给一个对延迟敏感的在线接口服务配上吞吐优先的回收器,表现出来就是"平时很快,偶尔很慢";反过来给一个纯粹追求总处理量的离线批处理任务配上低延迟优先的回收器,则是在浪费本可以用来提升吞吐的计算资源。回收器的选择要对齐服务本身的性能目标,而不是全公司所有服务统一套用同一份默认配置。

大对象分配:一个容易被忽视的压力源

内存分配通常有一套快速路径,针对的是生命周期短、体积不大的常规对象。但当代码里频繁创建体积明显偏大的对象(比如一次性读入过大的文件内容到内存、拼接巨大的字符串、构造超长的集合),这些大对象往往会绕过常规的快速分配路径,直接进入需要更昂贵处理方式的内存区域。

这类分配模式带来的后果是:老年代(或者更昂贵的内存区域)的压力被不合理地提前加重,导致回收频率和停顿时长都比正常情况下更差,而且这种压力往往不是均匀出现的,而是跟着某个特定的业务操作(比如批量导出、大文件处理)周期性出现,表现为"偶尔一阵 GC 特别猛"。排查这类问题的方向是审视代码里是否存在不必要的大对象分配,能不能通过分批处理、流式处理来避免一次性构造巨大对象,这和批处理任务的分批限速思路是一致的,见 批处理与 ETL 数据管道运维 中关于分批处理的讨论。

堆外内存:垃圾回收器看不见的盲区

垃圾回收器管理的是堆内内存,但现代应用的内存占用经常有相当一部分落在堆外——网络连接的缓冲区、压缩解压用到的临时缓冲、某些底层库直接管理的内存。这部分内存不受垃圾回收的调度和统计,常规的 GC 监控指标完全看不到它,但它照样会消耗系统的物理内存,极端情况下照样能把进程挤爆。

排查内存问题时,如果堆内的各项指标看起来都正常,但进程整体内存占用依然在持续上涨,就要把排查方向转向堆外,具体的排查思路和内存泄漏的堆外内存排查是同一套方法,见 内存泄漏与 OOM 排查 中关于 RSS 与堆差值的讨论。容器环境下还要额外注意,容器的内存上限计算的是进程总内存(堆内加堆外),只按堆内配置去推算容器限制是不够的。

调优前必须先量化的三个指标

调整垃圾回收相关的参数是一次高风险的变更,凭感觉改一个参数值再看看效果如何,是最低效也最容易踩坑的做法。调优应该从量化现状开始:

  • 停顿的分布情况:不只是平均停顿时长,更重要的是停顿时长的分布——有多少次停顿超过了业务能容忍的阈值,这些超标的停顿占比是多少。只看平均值会把少数几次拖垮 P99 的严重停顿平均掉,看起来一切正常。
  • 回收频率与总耗时占比:单位时间内垃圾回收总共占用了多少 CPU 时间,这个占比如果持续偏高,说明堆的整体容量规划可能存在问题,而不只是停顿策略的问题。
  • 各代际(或对应的内存区域)的回收触发模式:不同代际的回收代价和频率差异很大,搞清楚具体是哪个区域的回收在拖慢系统,才能有针对性地调整,而不是整体调大一个笼统的堆参数。

有了这些量化数据之后再做调整,并且每次只调整一个变量、观察一个完整的业务周期,才能确认这次调整真正带来了改善,而不是和其他波动混在一起无法判断因果,调整的风险管理和其他高风险配置变更是同一套原则,见 超时设置与重试策略 中关于参数变更谨慎性的讨论。

常见坑

  • 简单调大堆试图减少 GC 频率:忽视了单次停顿时长会相应拉长,对延迟敏感的服务反而变得更不稳定。
  • 全公司所有服务统一套用同一份回收器配置:吞吐优先和延迟优先的场景被一刀切处理,各自的表现都没有达到应有的水平。
  • 不查代码里的大对象分配就直接调参数:根因在应用代码里,参数调整只是在给症状打补丁。
  • 只监控堆内指标,忽视堆外内存的持续增长:进程整体内存照样被挤爆,GC 监控曲线却显示一切正常。
  • 调优时一次改多个参数:观察到的效果变化无法归因到具体哪个调整,下次遇到问题还是不知道该怎么改。

常见问题

GC 停顿导致的延迟尖刺,应该怎么快速定位是不是真的是 GC 问题?

把应用的 GC 日志或指标和延迟监控的时间轴对齐,看延迟尖刺是否和 GC 停顿事件在时间上吻合。如果吻合度很高,基本可以确认是 GC 导致;如果延迟尖刺和 GC 事件对不上,就需要去别处排查,不要先入为主地归因到 GC。

堆设置得越大是不是就意味着 OOM 的风险越低?

降低了因为堆空间不足触发 OOM 的风险,但同时增加了单次停顿变长的风险,而且堆设置要和容器或宿主机的物理内存上限匹配,设置过大反而会在内存紧张时让整个进程被系统强制终止,这类风险见 内存泄漏与 OOM 排查 中关于容器内存上限与运行时堆配置对齐的讨论。堆大小是一个需要综合考量的平衡点,不是越大越安全。

低延迟优先的回收器是不是总比吞吐优先的更好?

不是。低延迟优先的回收器为了压缩停顿时间,通常会消耗更多的 CPU 资源用于并发处理,如果机器的 CPU 资源本来就紧张,或者业务对吞吐量比延迟更敏感,低延迟优先的回收器反而可能让整体表现变差。选择要基于具体业务的性能目标,不存在普遍意义上更好的选项。

代码层面能做什么来减轻垃圾回收的压力,而不只是调整回收器参数?

减少不必要的对象创建,尤其是避免在高频路径上反复创建短生命周期但体积较大的对象;复用对象而不是每次都重新分配;对于确实需要处理大块数据的场景,优先考虑流式或分批处理而不是一次性加载到内存。这些代码层面的优化往往比单纯调整回收器参数更有效,也更治本。

资料来源

主流编程语言运行时关于垃圾回收算法与调优参数的官方文档,以及服务端性能工程领域关于 GC 停顿分析与内存管理的通用技术资料。本文为通用运维说明,仅供参考,具体机制与可调参数以实际运行时版本为准。

相关阅读

网站访问日志留存与安全合规运维要点

为什么要留日志:这是法定要求 《网络安全法》第二十一条明确要求网络运营者"采取监测、记录网络运行状态、网络安全事件的技术措施,并按照规定留存相关的网络日志不少于六个月"。已完成备案、对外提供服务的网站属于网络运营者范畴,日志留存不是可选项,而是基础合规义务。 应留存哪些日志 | 日志类型 | 记录内容 | 主要用途 …

网站新增域名如何补充接入备案

企业在原有网站基础上新增域名,比如启用新的品牌域名或拼音域名指向同一网站时,不能直接绑定使用,而是需要在原备案基础上补充办理新增域名的接入手续。 新增域名前的准备工作 新增域名前,建议先确认该域名已经完成实名认证,可以通过 Whois查询 核对域名的注册信息和实名状态,避免因域名信息未实名导致接入申请被退回。同时确认…

备案信息年度核查该如何配合应对

部分省份的通信管理部门会对辖区内已备案网站开展年度或不定期核查,核查方式包括系统比对、电话回访、短信确认等,目的是确认备案信息与网站实际运营情况是否一致。 核查通常关注哪些内容 年度核查一般围绕主体信息、网站信息、接入信息三个维度展开,具体可以对照下表自查: | 核查维度 | 常见核查点 | | --- | --- …

备案号在网站上的规范展示与使用要求

网站完成备案只是第一步,备案号在页面上的展示方式同样需要长期维护,很多主体正是因为展示细节不规范,在日常巡查或年度核查中被要求整改。 展示位置与基本要求 通常做法是将备案号放置在网站首页底部,文字需清晰可辨、不被图片或广告遮挡,且格式应与下发的备案号文本保持一致,不能随意增减字符或调整顺序。是否需要加超链接指向查询入…

备案注销之后重新申请要注意什么

有些主体在此前因业务调整、接入商变更等原因注销了原有备案,之后又因新的业务需要重新申请备案。这种“二次备案”与首次备案在流程上大体相似,但有几个环节容易被忽略。 重新申请前的自查 重新申请前,建议先用 ICP备案查询 确认原备案是否确实已经完成注销,避免出现原备案未彻底清空、新申请与旧记录冲突的情况。同时检查计划使用…

备案信息变更有没有时效要求

备案不是办理完成后就一劳永逸的事项,主体信息、网站信息或联系方式一旦发生变化,通常需要在信息变化后的一定时间内完成变更提交,具体时限以属地管局要求为准。 哪些变化需要及时申报 常见需要变更的情形包括:主办单位名称或证件信息变化、网站负责人更换、联系电话或邮箱失效、网站域名调整、网站内容服务类型发生实质变化等。这类变更…

公司迁址之后备案地址信息如何更新

企业办公地址或注册地址发生变化后,备案信息中登记的地址项也需要相应更新,尤其是当迁址涉及跨区、跨市甚至跨省时,办理流程会比同城内迁址更复杂一些。 迁址后需要关注的信息 迁址后首先要确认工商登记信息是否已经完成同步变更,备案地址一般以工商登记的最新地址为准。可以先用 ICP备案查询 查看当前登记的主办单位地址,与最新的…

备案预留手机号邮箱变更该如何更新

备案信息中登记的手机号和邮箱,是管局与接入服务商联系网站负责人的主要渠道,用于发送核查通知、验证短信、审核结果等重要信息。这些联系方式一旦更换却未同步更新,容易导致关键通知被漏收。 常见需要更新的场景 负责人更换手机号或离职导致原号码停用; 企业邮箱系统迁移,原邮箱地址不再使用; 备案负责人变更,联系方式随之更换。 …

系统学习