吞吐量=用户代码运行时间/(用户代码运行时间+gc总耗时),通过总观测时长减gc总耗时反推;延迟需关注stw停顿尾部分布(如p95、p99)及full gc;须过滤并发阶段、元空间回收和系统抖动等非stw干扰项。

分析 GC 日志里的吞吐量与延迟,核心是提取两类关键时间:用户代码运行总时长(隐含)、GC 总耗时(显式)、单次停顿时长(显式)。不需要复杂工具,靠日志原始字段就能算出真实指标。
看吞吐量:从 GC 时间占比反推
吞吐量 = 用户代码运行时间 / (用户代码运行时间 + GC 时间),而日志中不直接记录“用户代码运行时间”,但可以反推:
- 统计一段时间内所有 GC 事件的耗时总和(比如 1 小时内所有 GC 的 “user”、“sys”、“real” 时间之和,优先用 real 时间)
- 用总观测时长减去 GC 总耗时,即为近似用户代码运行时间
- 例如:60 分钟(3600 秒)内 GC 总耗时 120 秒 → 吞吐量 ≈ (3600 − 120) / 3600 = 96.7%
注意:如果日志中频繁出现 long pause(如 >500ms),即使吞吐量数值高,也说明存在不可接受的延迟风险——吞吐量掩盖不了单点卡顿。
抓延迟:聚焦 STW 停顿的真实分布
延迟不是看平均值,而是看尾部。重点扫描日志中带 Pause、GC pause、Pause Young、Pause Full 等关键词的行:
- 提取每条记录的停顿时间(单位通常是 ms,如 "pause: 182.4ms" 或 "real=0.182s")
- 按时间窗口(如每 5 分钟)统计最大停顿、P95 停顿(即 95% 的 GC 停顿 ≤ 该值)
- 特别标记 Full GC 行为:G1 的 Mixed GC 不等于 Full GC;只有明确含 "Full GC" 或 "Pause Full" 的才是全局停顿
例如某电商支付接口要求 P99 ≤ 100ms,若日志显示过去一小时有 3 次停顿为 320ms、280ms、190ms,则已超标。
识干扰:过滤无效或误导性数据
不是所有“GC 时间”都代表应用停顿。需区分三类非 STW 活动:
- 并发阶段:G1 的 Concurrent Mark、ZGC 的 Concurrent Mark/Relocate,这些线程与用户线程并行,不计入停顿
- 元空间回收:Metaspace GC(如 "Metadata GC Threshold")通常不触发 STW,不影响响应延迟
- 系统抖动:real 时间远大于 user+sys(如 real=0.3s, user+sys=0.05s),大概率是 OS 调度延迟或 I/O 等待,不是 GC 本身问题
这类条目可归入“背景噪音”,分析吞吐与延迟时不纳入计算,否则会高估 GC 开销。
连业务:把 GC 指标和请求链路对齐
单独看 GC 日志容易误判。建议同步采集应用监控(如 Prometheus 的 http_server_requests_seconds_count):
- 在 GC 停顿密集时段,观察 TP99 是否同步飙升、错误率是否跳升
- 若某次 Full GC 发生后,紧接着出现一批 5xx 错误或超时,基本可确认因果关系
- 避免“日志有 GC,业务就慢”的归因陷阱——有些慢请求根本没触发 GC,而是数据库锁或网络重试导致
真正有效的分析,是让 GC 数据说话,而不是替它下结论。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











