吞吐量是全局统计指标,需基于整个观测时段计算,公式为(总运行时间−GC总耗时)÷总运行时间×100%,其中GC总耗时含所有GC事件real值之和,Full GC频次与单次耗时共同影响整体吞吐量。

Full GC 期间的应用吞吐量,不能单独按某一次 Full GC 计算——因为吞吐量是**全局统计指标**,反映的是整个观测时段内用户代码运行时间占总时间的比例。单次 Full GC 只影响延迟(停顿),不定义吞吐量。真正要算的,是“包含 Full GC 在内的整段日志周期内”的整体吞吐量。
吞吐量核心公式不变
无论有没有 Full GC,吞吐量始终按这个公式算:
吞吐量 = (总运行时间 − GC 总耗时) ÷ 总运行时间 × 100%
其中:
- “总运行时间” = 日志首行时间戳到末行时间戳的差值(单位:秒)
- “GC 总耗时” = 所有 GC 事件的 real=xxx secs 值之和(包括 Young GC、Mixed GC、Full GC)
Full GC 的 real 时间通常远大于 Young GC(比如 0.2s vs 4.2s),它会显著拉高 GC 总耗时,从而压低整体吞吐量。例如:2 小时日志(7200 秒)中,若 Full GC 发生 3 次,每次 real≈3.5 秒,仅这三项就贡献 10.5 秒停顿——如果其他 GC 累计 9.5 秒,总 GC 耗时就是 20 秒,吞吐量 = (7200−20)/7200 ≈ 99.72%;但若 Full GC 达 20 次、平均 4 秒,光它就占 80 秒,吞吐量直接掉到 98.89%。
Full GC 对吞吐量的影响更要看频次和占比
不是一次 Full GC 就让吞吐量崩盘,而是它的累积效应。重点关注:
将后端 Java 接口文档转换为前端 TypeScript 类型定义(interface / type)。输入:飞书文档、Spring Boot 接口文档、Swagger/OpenAPI、手写 API 文档等。输出:包含请求参数与响应结果的 .md 文件,含完整 JSDoc 注释。触发关键词:Java 转 TS、接口转换、生成前端类型、接口文档转 TypeScript、DTO/VO/BO 转 interface、后端文档转前端类型、生成接口类型、类型定义生成。
- Full GC 次数占全部 GC 次数的比例(如 >5%,需警惕)
- Full GC 总耗时占 GC 总耗时的比例(如 >40%,说明老年代压力大,即使次数少也伤吞吐)
- 两次 Full GC 之间的间隔是否持续缩短(趋势性恶化)
比如某服务每小时发生 12 次 Full GC,平均每次 real=2.8s,则 Full GC 耗时 = 33.6s/小时;若该小时总运行时间 3600s,其他 GC 耗时 26.4s,则 GC 总耗时 60s → 吞吐量 = 3540/3600 = 98.3%。这个数值看似尚可,但已逼近 Web 服务健康水位(通常要求 ≥99%)。
别把 Full GC 和吞吐量混淆成因果关系
Full GC 是现象,吞吐量下降是结果之一。但根本原因往往在它之前:
- 对象过早晋升(年轻代太小或 Survivor 区溢出)
- 内存泄漏(缓存未清理、静态集合无界增长)
- 元空间频繁回收触发 Full GC(-XX:MetaspaceSize 设置过低)
- 显式调用 System.gc()(日志中可见 “System.gc()” 字样,应禁用)
分析时先用 grep "Full GC\|System\.gc" gc.log 定位所有 Full GC 行,再结合堆内存变化(如 jstat -gc 输出的老年代使用率趋势)判断是偶发还是持续恶化。
实际计算建议步骤
拿到一段含 Full GC 的 GC 日志后,按顺序做三件事:
- 开启日志参数确保字段完整:-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/path/to/gc.log
- 提取首尾时间戳算总运行时间(推荐用 date -d 解析 ISO 时间,避免手动计算)
- 用 awk 或脚本累加所有 real= 值:awk '/real=[0-9.]+s/ {gsub(/.*real=/,"",$0); gsub(/s.*/,"",$0); sum += $0} END {print sum}' gc.log
最后套入公式即可。注意:jstat 的 FGCT 是 CPU 时间总和,不等于日志中 real 累加值,后者才是计算吞吐量的准确依据。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










