线上服务器内存飙升到90%排查方法
这是一个典型的 Java 线上内存问题,可以按「应急止血 → 定位根因 → 长期根治」三个阶段来处理。下面给你一套可直接用于生产环境的标准排查流程。
一、应急止血(先保系统)
目标:不让服务继续恶化,争取排查时间
1️⃣ 快速判断是不是 Java 进程吃内存
top # 或 ps -aux | grep java重点关注:
RES / RSS:常驻内存
%MEM
Java 进程是否持续上涨不回落
✅ 如果非 Java 进程导致,直接处理对应进程即可。
2️⃣ 临时缓解手段(可立即执行)
场景 | 操作 |
|---|---|
内存快打满 | 临时扩容机器 / 增加 swap |
无法立即重启 | 降低流量(限流、切流) |
已影响业务 | 优雅重启服务 |
⚠️重启前务必保留现场(见第二节)
二、线上定位(核心)
✅ Step 1:确认是哪种内存问题
Java 内存 =Heap + Non-Heap + Off-Heap
1. 查看 JVM 内存概况
jstat -gc <pid> 1000 10关注指标:
OU:Old 区使用量(是否持续增长)YGC / FGC:GC 次数 & 时间FGCT:Full GC 时间是否过长
📌现象判断表
现象 | 可能原因 |
|---|---|
Old 区一直涨 | 内存泄漏 |
Full GC 频繁但回收少 | 对象无法释放 |
Heap 正常但 OS 内存高 | Direct Memory / JNI / 线程 |
Metaspace 增长 | 动态类加载 |
✅ Step 2:抓取堆内存快照(最重要)
⚠️必须提前预留磁盘空间(≥ 1.5 × 最大堆)
jmap -dump:live,format=b,file=heap.hprof <pid>或自动触发(推荐):
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/logs/✅ Step 3:分析 Heap Dump(本地分析)
工具推荐:
MAT(Memory Analyzer)
VisualVM
JProfiler
重点看:
Dominator Tree
Histogram
GC Roots
📌 常见泄漏点:
静态
Map / List / Cache线程池未释放
监听器 / 回调未注销
Session / 连接池泄漏
本地缓存(Guava Cache 无过期)
✅ Step 4:排查非堆内存(非常关键)
1️⃣ 查看 JVM 各区域
jcmd <pid> VM.native_memory summary重点:
Java HeapClass (Metaspace)ThreadCodeInternal
2️⃣ 常见 Off-Heap 泄漏
类型 | 说明 |
|---|---|
DirectByteBuffer | Netty / NIO |
JNI | C 堆泄漏 |
线程栈 | 线程数暴涨 |
Zip / 解压流 | 未 close |
📌 Netty 项目90% 是 Direct Memory 问题
✅ Step 5:线程排查(防止隐形内存杀手)
jstack <pid> > jstack.log检查:
线程数是否异常(几千个)
是否有大量:
WAITING (parking)BLOCKED自定义线程池
三、典型真实案例(对照参考)
🔴 案例 1:静态 Map 缓存泄漏
static Map<String, Object> cache = new HashMap<>();✅ 解决:
改用
WeakHashMap或设置 TTL(Caffeine)
🔴 案例 2:Netty Direct Memory 泄漏
-XX:MaxDirectMemorySize 未限制✅ 解决:
-XX:MaxDirectMemorySize=2g并监控:
BufferPoolMXBean🔴 案例 3:线程池无限增长
Executors.newCachedThreadPool()✅ 解决:
使用
ThreadPoolTaskExecutor设置队列 + 拒绝策略
四、长期根治方案(必做)
✅ JVM 参数优化示例
-Xms4g -Xmx4g -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:+HeapDumpOnOutOfMemoryError -XX:NativeMemoryTracking=summary✅ 监控体系建设
监控项 | 工具 |
|---|---|
JVM 内存 | Prometheus + JMX Exporter |
GC | GC 日志 |
线程数 | Micrometer |
Direct Memory | BufferPoolMXBean |
OOM 告警 | 企业微信 / 钉钉 |
五、标准排查 checklist(可直接给运维)
✅ 是否 Heap 泄漏
✅ 是否 Metaspace 过大
✅ 是否 Direct Memory 未限制
✅ 是否线程数异常
✅ 是否缓存无过期
✅ 是否第三方 SDK Bug
六、我可以继续帮你做的事
如果你愿意,可以把下面信息发我,我可以直接帮你判断根因:
JVM 参数(
ps -ef | grep java)jstat -gc输出使用的框架(Spring Boot / Netty / MQ)
内存增长曲线(是否线性)
