real − user − sys 差值≥3ms且反复出现在Young GC中,是物理CPU核心抢占的关键证据;需结合vmstat的r列、mpstat的%steal/%irq及perf调度分析交叉验证,并通过cgroup或K8s CPU Manager实施硬隔离。

看 GC 日志里的 Times: user=xx sys=xx real=xx,不是只比大小,而是要算差值——real − user − sys 这个“等待时间”才是物理 CPU 核心被抢占的关键证据。
理解 user、sys、real 的真实分工
user:JVM GC 线程在用户态干的活,比如扫描对象图、复制存活对象,纯计算耗时。
sys:GC 过程中掉进内核态的时间,例如分配内存页、获取同步锁、处理 TLB miss。
real:从 GC 开始到结束的墙钟时间,包含所有不可控等待——调度排队、核心争抢、上下文切换。
三者不满足加法关系。当 real 明显大于 user + sys(差值 ≥ 3ms 且反复出现),尤其集中在 Young GC 中,说明 GC 线程已准备好执行,但迟迟没分到物理核心,正在队列里等调度。
Miller (mlr) 是一个命令行工具,用于查询、整形和重新格式化名称索引数据,如 CSV、TSV、JSON 和 JSON Lines。它将 awk、sed、cut、join 和 sort 的功能整合到一个专为结构化数据处理而构建的单一工具中。
识别核心抢占的典型日志模式
- 同一台机器上多个 Java 进程的 GC 日志中,real 比 user+sys 高出 3–10ms 以上,且波动剧烈
- Young GC 的 user 和 sys 很稳定,real 却突然拉长(计算和内核开销没变,只是“轮不到执行”)
- G1 或 Parallel GC 显示 “GC Workers: 8”,但 real 接近单线程耗时 × 8(说明线程并行度失效,实际是串行排队)
- 差值(real − user − sys)与 vmstat 1 中的 r 列(可运行进程数)峰值强相关,例如 r ≥ CPU 总逻辑核数 × 1.5
必须联动系统指标交叉验证
仅看 GC 日志不能下结论。需立刻检查:
- 运行 mpstat -P ALL 1:若各核 %iowait 很低,但 %steal(宿主机超卖)或 %irq(中断风暴)异常高,指向底层资源争抢
- 查 /proc/<pid>/stat 中的 utime/stime(用户/内核累计时间)增长缓慢,而 cutime/cstime(子进程时间)突增 → 其他进程吃满 CPU
- 用 perf record -e sched:sched_switch -p <pid> -g -- sleep 10,再 perf script | grep -A5 "java":若频繁看到 R state → S state 切换,说明线程长期就绪却未被调度
收敛环境,从根源降低抢占
这不是调 -XX:ParallelGCThreads 能解决的,关键在运行时资源硬隔离:
- 容器部署时,禁用 cpu.shares 这类软性权重,改用 cpu.cfs_quota_us + cpu.cfs_period_us 设置硬上限
- Kubernetes 中为关键 Java Pod 配置 resources.limits.cpu 并启用 static CPU manager policy,绑定独占核心
- 避免在同一物理机混部多个高并发 Java 服务;若必须共存,通过 taskset 或 cgroup v2 的 cpuset 控制器严格划分核心归属

















