若sys/real>20%或real明显大于user+sys(差值≥5ms),表明存在Swap干扰;需结合vmstat的si/so、/proc/pid/smaps及meminfo交叉验证,并检查JVM堆配置与cgroup限制。

直接看 GC 日志里的 Times 字段,重点比对 sys 和 real 的关系——这是识别 Swap 干扰最灵敏的信号。
盯住 Times 字段里的三个时间
每次 GC 日志末尾类似这样的一行:
[Times: user=0.03 sys=0.08, real=0.150 secs]
其中:
- user:JVM 自身在用户态做的工作耗时(比如扫描对象、复制内存)
- sys:JVM 调用内核服务所花的时间(如缺页中断、swap I/O、内存映射)
- real:从应用线程被 STW 开始,到全部恢复的总墙钟时间
如果 sys / real > 20%(例如上面例子中 0.08 / 0.15 ≈ 53%),或 real 明显大于 user + sys 之和(差值 ≥ 5ms),基本可以断定内核参与过重,Swap 是首要嫌疑。
交叉验证 Swap 是否真被触发
光看日志不够,必须联动系统指标确认:
- 查
vmstat 1输出中的 si(swap in)和 so(swap out)列:只要任一列在 GC 时间点附近出现非零值,就坐实了 Swap 活动 - 执行
cat /proc/<java_pid>/smaps | awk '/Swap:/ {sum += $2} END {print sum/1024 " MB"}':直接看该 Java 进程当前用了多少 MB 的 Swap - 运行
grep -i "swap" /proc/meminfo:关注 SwapTotal、SwapFree、SwapCached,若 SwapFree 快见底,风险极高
定位是哪个进程或配置惹的祸
Swap 不是凭空来的,得找到根源:
- 检查 JVM 堆配置是否过大:比如
-Xms4g -Xmx4g在一台只有 8G 物理内存的机器上,又没关 swap,极易触发换页 - 用
for i in /proc/[0-9]*; do awk '/Swap:/ {a+=$2} END{if(a>0) print "'$i'", a/1024"M"}' $i/smaps 2>/dev/null; done | sort -k2nr找出真正吃 Swap 的进程 PID - 确认是否运行在容器中:若启用了 cgroup v1 且
memory.limit_in_bytes设置过紧,也会强制触发 swap-like 行为,抬高 sys 时间
临时缓解与长期规避
发现问题后,分两步走:
-
应急:关闭 swap(
swapoff -a)或限制其使用(sysctl vm.swappiness=1),并重启 Java 进程 -
根治:调低 JVM 堆大小(如从 4G 改为 2G),确保
heap + native memory + OS buffer/cache总和明显小于物理内存;生产环境建议禁用 swap,或仅保留极小 swap 作兜底


















