JVM GC长暂停问题排查
现象
名词:GC 垃圾回收(Garbage Collection)分类 计算机科学
在高并发下,Java程序的GC问题属于很典型的一类问题,带来的影响往往会被进一步放大。不管是「GC频率过快」还是「GC耗时太长」,由于GC期间都存在Stop The World问题,因此很容易导致服务超时,引发性能问题。
事情最初是线上某应用垃圾收集出现Full GC异常的现象,应用中个别实例Full GC时间特别长,持续时间约为15~30秒,平均每2周左右触发一次;
JVM参数配置“-Xms2048M –Xmx2048M –Xmn1024M –XX:MaxPermSize=512M”
-
周期性长暂停
- 线上Java应用每2周触发1次Full GC
- 单次暂停15-30秒(正常Full GC应≤1秒)
- 仅部分实例出现,JVM配置一致(
-Xms2048M –Xmx2048M –Xmn1024M –XX:MaxPermSize=512M
)
-
异常GC特征
- Full GC原因标记为
Ergonomics
(JVM自适应策略触发) - GC日志未显示堆内存异常(回收前后内存占比正常)
- Full GC原因标记为
背景
-
系统环境
- 部署于 Linux虚拟机(物理内存8GB)
- 关键参数:
vm.swappiness=30
(默认倾向使用SWAP)
-
并发场景
- 高QPS服务:持续内存分配压力
- 内存使用特点:
监控项 现象 物理内存 未完全耗尽( free
显示可用内存充足)SWAP分区 占用305MB(进程检测) CPU Full GC时骤增
-
矛盾点
- JVM认为内存充足(堆配置仅2GB),但OS将部分内存页换出到SWAP磁盘
- 低频率Full GC(2周1次)→ 内存页在SWAP停留时间长 → GC遍历时触发磁盘换入
核心冲突示意图
JVM Full GC
│
├─ 需遍历堆内存
│ │
│ ├─ 内存页在物理内存 → 微秒级访问
│ │
│ └─ 内存页在SWAP磁盘 → 毫秒级磁盘I/O(**10^3倍延迟**)
│
└─ 大量页换入操作阻塞GC线程 → **STW时间膨胀至秒级**
关键结论:低频Full GC + SWAP换出 + 遍历换入需求 = 长暂停灾难链
第一层:核心概念定义
-
JVM与GC机制
- Java虚拟机(JVM)通过垃圾回收(GC)管理内存,GC执行时会触发"Stop The World"(STW)暂停
- Full GC:清理整个堆内存的回收操作,耗时显著
-
问题现象
- 某应用实例周期性出现15-30秒Full GC
- JVM配置:
-Xms2048M –Xmx2048M –Xmn1024M –XX:MaxPermSize=512M
- Full GC诱因:Ergonomics(自适应策略触发)
第二层:系统级分析
-
GC日志与服务器指标关联
- GC日志显示回收前后堆内存无异常
- 监控发现Full GC时点出现:
- CPU使用率骤增(图1红框)
- 物理内存增长拐点 + SWAP区释放(图1橙框)
-
SWAP机制验证
# 检测进程SWAP占用 for i in $(cd /proc; ls | grep "^[0-9]" | awk '$0>100'); do awk '/Swap/{a=a+$2} END{print '"$i"',a/1024"M"}' /proc/$i/smaps 2>/dev/null done | sort -k2nr | head -10
- 目标进程占用SWAP 305MB
- 异常实例swappiness=30(倾向使用SWAP),正常实例swappiness=0
第三层:根因分析
-
SWAP与GC的致命交互
- Linux内存压力时:物理内存页换出到SWAP(swap out)
- Full GC遍历堆内存时:SWAP数据换回物理内存(swap in)
- 磁盘I/O操作导致GC遍历耗时剧增(从毫秒级→秒级)
-
对比实验佐证
场景 SWAP用量 Full GC耗时 关键差异 问题实例(2周1次) 305MB 15-30秒 内存页被换出至SWAP 实名服务(几小时1次) 54MB 576ms SWAP无活动+频繁GC避免换出
第四层:解决方案
-
临时措施
sysctl vm.swappiness=0 # 禁用SWAP倾向 swapoff -a # 关闭SWAP分区(需确保物理内存≥SWAP用量)
-
永久配置
vm.swappiness=0
-
效果验证
- 关闭SWAP后Full GC耗时降至190ms(图2橙框)
基座:延伸思考
-
关键疑问解答
- Q:SWAP是否必然导致GC卡顿?
A:否!仅当GC时发生swap in操作才会引发(实名服务证明) - Q:JVM为何不禁用SWAP?
A:Linux内存管理需平衡安全性与性能(kswapd守护进程机制)
- Q:SWAP是否必然导致GC卡顿?
-
最佳实践
- 高并发服务建议:
vm.swappiness=0
+ 足够物理内存 - 备选方案:降低堆大小(避免内存换出)
- 高并发服务建议:
-
核心结论复述
SWAP与GC同时触发→内存页换入换出→磁盘I/O阻塞STW→秒级卡顿,通过禁用SWAP或优化内存配置可根治。
原文参考https://blog.csdn.net/cnzzs/article/details/141273193