Java GC 日志暂停原因 怎样处理
来源:17golang原创
时间:2026-10-22 08:36:25 352浏览 收藏
Java GC 日志暂停原因 怎样处理
接口突然变慢,恰好看到一条 GC 日志,并不足以说明垃圾回收就是根因。值班时更有用的做法,是先圈定同一进程的异常时间窗,再分清停止应用线程的暂停、并发工作和到达安全点的等待。本文以 G1 为范围,采用 JDK 26 文档中的统一日志配置;其他 JDK 版本的字段与措辞可能不同,不能套用关键词硬判。
官方文档地址,可复制查阅:https://docs.oracle.com/en/java/javase/26/gctuning/garbage-first-garbage-collector-tuning.html。本文给出的是排查操作手册,不是线上故障复盘,命令和记录样例未在你的服务执行。
一、先确认处理的是哪个进程、哪段时间
先保存部署版本、JDK 版本、实际启动参数、收集器、实例标识、启动时间和业务异常起止时间。不要仅凭机器安装了某个 java,就认定运行中的服务使用相同版本;也不要为了排查而直接更换收集器。本文只处理已经使用 G1 的服务。
时间窗应覆盖异常前后,保留应用延迟、流量、CPU 配额与内存限制的同期信息。进程重启后,运行时长和 GC 编号的上下文会改变;两份日志里的 GC(12) 不是天然同一事件。跨实例日志必须先按实例和本次启动分组。
二、以有限轮转开启日志,不把诊断变成新的负担
下面是获授权环境中修改现有启动命令的配置片段。先创建应用用户可写、容量受监控的日志目录,再合入现有 JVM 参数,不要额外启动第二个生产实例。app.jar 是占位文件,其他业务参数与既有配置需要保留。
# 示例:在已有启动配置中加入统一日志选项;不要原样启动第二个服务 java '-Xlog:gc*,safepoint:file=logs/gc-%p-%t.log:time,uptime,level,tags:filecount=5,filesize=20M' -jar app.jar
time 便于关联业务时钟,uptime 用于观察同一 JVM 内的相对位置。%p 与 %t 有助于隔离进程和启动批次,但不是全局实例身份证明。轮转大小是日志管理参数,不是严格磁盘容量上限;多次启动产生的文件集仍需按保留策略清理。限制访问权限,避免把内部运行信息公开到下载目录。
默认信息级别先帮助定位类型。若需要更细的阶段数据,可在受控短窗口采用 -Xlog:gc+phases=debug;应把它与现有输出方案一并规划,而不是无限叠加日志选项。详细日志可能增加开销,记录开启和结束时间,结束后恢复原日志配置。统一日志语法见文末 java 命令文档。
三、按 GC 编号归并:只统计暂停汇总,不重复相加
先找带 Pause 的完成汇总行,看它属于 Young、Mixed 还是 Full,再沿相同 GC 编号读开始行和阶段明细。不要把开始行算一次、完成行再算一次,也不要把子阶段耗时再叠加到总暂停上。并行工作线程耗时的统计口径也不能当作串行墙钟时间相加。
Young 和 Mixed 不意味着“没有暂停”;Concurrent Mark 等并发阶段的整个持续时间也不等于应用停止时间。一个并发周期可能包含需要暂停的环节,应分别读取对应暂停记录。日志原因文本是触发线索,不是完整根因报告。

例如,假设某个并发周期跨越 900 毫秒,期间有两次分别为 8 和 12 毫秒的暂停,不能据此宣布应用停顿 900 毫秒。这里的数字仅解释统计口径,不是实际日志或性能结果。窗口内汇总暂停时间、最大暂停和次数时,还要写清跨窗口事件如何归属,避免不同报表口径冲突。
四、把安全点等待与 GC 阶段开销分开
安全点记录中的到达安全点时间,与所有相关线程已经停下之后执行工作的时间不是同一指标。读取当前版本实际输出的字段和单位,分别记录 reaching safepoint、at safepoint 及 total 等信息;不同版本可能额外区分清理阶段。安全点也可能由非 GC 操作触发,不能把每条 safepoint 都归类为 GC。
如果等待到达安全点突出,应结合线程状态、系统调度和 CPU 资源继续定位;如果暂停主体突出,再看引用处理、根扫描、对象复制等阶段。两类证据可以同时异常。单条日志不能证明是哪一个业务线程造成,也不能仅凭这一点给第三方组件定责。
GC CPU 行中的 User、Sys、Real 是不同口径,且并行执行时 User 可以大于 Real。Real 明显偏高时,应把同期 CPU 争抢、容器限额和系统压力纳入调查,不要直接把它解释为“堆太小”。没有业务时间相关性时,也应保留继续排查数据库、锁竞争或下游请求的路径。
五、依证据选择一项动作,而不是复制一组调优参数
| 观察到的线索 | 继续确认什么 | 有边界的处置方向 |
|---|---|---|
| Full 暂停,附近存在疏散失败线索 | 失败原因、回收后占用、分配压力、并发周期是否来得及完成 | 先定位对象生命周期与容量约束,不直接归为内存泄漏 |
| 复制或扫描相关阶段突出 | 连续多个同类事件,是否与业务对象数量或引用关系变化同步 | 优先减少不必要的存活对象或分配,单次调整后观察 |
| 到达安全点等待突出 | 同时间线程和调度证据,是否为非GC安全点 | 转向线程执行与资源调查,不先压低暂停目标 |
| Real 异常但资源压力也变化 | CPU配额、宿主争抢、系统开销及业务负载 | 先恢复可比较的资源条件,再谈收集器参数 |

G1 的暂停目标不是硬实时保证。降低目标可能改变回收节奏,不能保证接口延迟一定下降;扩大 Java 堆也不能忽略容器总内存中的非堆、线程栈和其他进程预算。固定年轻代大小会限制 G1 自身的调整空间,不宜作为默认修复动作。
若触发原因涉及显式 GC,先确认调用者与用途,再评估是否修改调用方式;不要用全局禁用选项掩盖尚未识别的依赖。堆转储或强制诊断也可能有停顿和敏感数据风险,不属于本文默认操作。
六、交接时给出结论等级和回退条件
记录至少应包含实例与启动批次、异常时间窗、收集器、暂停次数和最大值、主要事件类型、安全点等待、同期资源与流量、证据缺口、单项变更和回退入口。可以写“当前证据支持GC暂停参与延迟”,不要在没有对照时写“已经证明全部延迟由GC造成”。
变更前后使用相近负载和同一统计口径,兼顾吞吐、错误率、业务尾延迟和内存余量。若错误或资源风险增加,按原部署配置回退;若日志不足,补充限定窗口的观察,不反复改参数碰运气。结束诊断后恢复日志级别,保留必要材料并按访问和保留策略归档。
参考:Oracle G1 调优指南;java 命令与统一日志。处理这类问题的关键不是见到 GC 就调堆,而是把暂停、并发和等待分开,再用同一时间窗内的证据决定下一步。
-
501 收藏
-
文章 · java教程 | 1个月前 | Java · 异常处理 · 资源管理 · java try-with-resources AutoCloseable close suppressed exception501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
232 收藏
-
382 收藏
-
465 收藏
-
493 收藏
-
文章 · java教程 | 1小时前 | Java · 异步编程 · 性能排查 · java httpclient completablefuture 异步超时 HttpTimeoutException sendAsync485 收藏
-
473 收藏
-
150 收藏
-
文章 · java教程 | 1小时前 | Java · 事务 · 代理 · spring · 排错 · java Spring事务 @Transactional TransactionTemplate 事务代理 自调用114 收藏
-
192 收藏
-
484 收藏
-
441 收藏
-
181 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习