一、紧急处理
-
立即保存现场
# 生成Heap Dump(若未配置自动转储) jmap -dump:format=b,file=/path/to/gc_oom.hprof <pid> # 获取GC日志(若未开启) jstat -gcutil <pid> 1000 5 # 每1秒输出1次,共5次 -
临时缓解
# 关闭GC开销限制(不推荐长期使用) -XX:-UseGCOverheadLimit # 或增大堆内存 -Xmx4g → -Xmx8g
二、问题定位流程
1. 分析GC日志
-
检查Full GC频率和耗时
grep "Full GC" gc.log | awk '{print $NF}' | sort -n | tail -5 # 查看最长Full GC时间-
若单次Full GC时间 > 1秒或频率 > 5次/分钟,需优化。
-
-
评估回收效率
观察每次GC后老年代(OU)的释放量:jstat -gc <pid> | awk '{print $4,$8}' # 输出OU(老年代使用量)和FGC(Full GC次数)-
若
OU长期 >90% 且每次GC释放 <5%,表明对象存活率过高。
-
2. 检查内存使用模式
-
对象分配速率
使用jstat监控分配行为:jstat -gc <pid> 1000 | awk '{print $9,$10}' # YGCT(Young GC时间)和YGC(Young GC次数)-
若
YGC每分钟 >50 次,可能存在 短生命周期对象爆炸。
-
-
Heap Dump分析
用 Eclipse MAT 或 VisualVM 分析:-
查找 重复的大对象数组(如日志消息、缓存条目)。
-
检查 对象年龄分布(存活时间过长的对象本应在Young GC被回收)。
-
3. 排查代码问题
-
常见内存反模式:
// 案例1:无限增长的集合(未清理) static List<Data> cache = new ArrayList<>(); // 案例2:大对象频繁分配(如每请求new大数组) byte[] buffer = new byte[10 * 1024 * 1024]; // 10MB/次
三、解决方案
1. 优化GC策略
-
切换垃圾回收器(示例配置):
# 改用G1 GC(适合大堆和低延迟) -XX:+UseG1GC -XX:MaxGCPauseMillis=200 # 或保持Parallel GC但调整策略 -XX:+UseParallelGC -XX:ParallelGCThreads=4 -XX:GCTimeRatio=19 # GC时间/应用时间=1/19 -
调整分代大小:
-Xmn2g # 增大年轻代(若对象存活时间短) -XX:SurvivorRatio=6 # Eden:Survivor=6:1:1(减少过早晋升)
2. 修复内存问题
-
案例1:缓存泄漏
修复方案:// 使用WeakHashMap或Guava Cache Cache<String, Data> cache = CacheBuilder.newBuilder() .maximumSize(1000) .expireAfterWrite(10, TimeUnit.MINUTES) .build(); -
案例2:大对象分配
修复方案:// 改用对象池或线程局部变量 private static final ThreadLocal<ByteBuffer> bufferHolder = ThreadLocal.withInitial(() -> ByteBuffer.allocate(1024));
3. 监控与限流
-
添加熔断机制:
if (memoryUsage > 0.9 * maxMemory) { throw new ServiceUnavailableException("System busy"); } -
Prometheus告警规则:
- alert: HighGCTime expr: sum(rate(jvm_gc_pause_seconds_sum[1m])) by (instance) > 0.5
四、验证与调优
-
基准测试
使用 JMeter 模拟高峰流量,观察:-
jstat -gcutil中的FGC和GCT是否下降。 -
应用吞吐量(TPS/QPS)是否恢复。
-
-
长期监控
-
GC日志分析工具(如 GCeasy)。
-
JVM Dashboard:监控
Old Gen Usage和GC Duration。
-
五、常见误区
-
误区:单纯增大
-Xmx-
后果:延长Full GC停顿时间,可能使问题恶化。
-
-
误区:禁用
GCOverheadLimit-
后果:掩盖问题,最终导致进程卡死。
-
-
误区:忽视外部依赖
-
如数据库返回超大结果集未分页。
-
六、完整参数配置示例
java \
-Xms4g -Xmx4g \
-Xmn2g \ # 年轻代占50%
-XX:+UseG1GC \
-XX:MaxGCPauseMillis=200 \
-XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=/var/log/gc_oom.hprof \
-XX:+PrintGCDetails \
-XX:+PrintGCDateStamps \
-Xloggc:/var/log/gc.log \
-jar myapp.jar
总结
-
定位:通过GC日志和Heap Dump确认是 内存泄漏 还是 分配速率过高。
-
解决:优化GC策略 + 修复问题代码 + 限制资源使用。
-
预防:监控 + 压测 + 代码审查(重点检查集合和缓存)。
核心原则:此异常表明GC已无法有效回收内存,需从 对象生命周期 和 回收算法 双向入手!
961

被折叠的 条评论
为什么被折叠?



