堆溢出解决思路

OOM:Java 堆溢出 java.lang.OutOfMemoryError: Java heap space

现象:‑Xmx 设置的最大堆内存被占满,GC 反复回收,回收后内存依然不够,抛出堆溢出。

一、定位步骤(排查思路)

  1. 开启堆 dump,发生 OOM 自动导出堆快照

    -XX:+HeapDumpOnOutOfMemoryError
    -XX:HeapDumpPath=/xxx/heap.hprof

程序 OOM 时自动生成 hprof 文件,用 MAT(Memory Analyzer Tool)(Eclipse 开源的内存分析工具,专门分析 hprof 堆转储快照文件,用来排查 Java 内存泄漏、堆 OOM)分析。

  1. MAT 分析 hprof 做三件事 ① 看大对象、支配树:是谁持有大量对象,是谁的引用链不让对象 GC。 ② 看对象数量:哪个类实例数量异常暴涨。 ③ 找泄漏点:对象本应该被回收,但被 GC Roots 强引用死死抱住。

区分两种完全不同情况:

  1. 内存泄漏(Memory Leak):对象不再业务使用,但存在强引用,无法 GC,内存只涨不降。
  2. 内存溢出(Memory Overflow):业务本身就需要这么多对象,内存给小了,没有泄漏。

二、情况 1:内存泄漏(最常见)

对象不用了,还被强引用持有,无法 GC。

常见泄漏场景

  1. 集合(List/Map)全局 static,只 add 不 remove,全局集合不断累积对象。
  2. ThreadLocal 没有 remove ();线程池线程复用,ThreadLocalMap 还持有对象引用。
  3. 监听器、回调注册,注销失败,引用没释放。
  4. 内部类持有外部类引用;匿名内部类捕获外部对象。
  5. 缓存没有设置淘汰策略(没有 LRU、过期时间),无限膨胀。

解决:

  • 不用的对象手动清除集合元素;
  • ThreadLocal 用完必须 remove;
  • 缓存增加最大容量、过期淘汰(Caffeine、Guava Cache);
  • 及时注销监听器回调;
  • 避免长生命周期对象持有短生命周期对象。

三、情况 2:没有泄漏,业务确实需要大量对象(堆内存配置过小)

例子:一次性查询百万数据全部加载进 List,全部放到内存。

MAT 看对象都是业务正常需要的,没有不该存活的对象。

解决思路二选一:

  1. 调高‑Xmx 堆内存,机器物理内存允许的前提下加大堆;
  2. 不要一次性全加载到内存,做流式处理 / 分页:分批读取、游标分页,不要把全量数据装入 List;使用迭代器逐条处理。

坑:select * from table 查出几十万行封装进 List,直接打爆堆,属于业务写法问题,不是泄漏。

四、代码层面临时优化手段

  1. 大对象尽量方法内局部变量,方法执行结束,无其他引用就可以 GC;
  2. 大集合用完置为 list=null,帮助 GC Roots 解除引用(更多是可读性,JVM 会自动识别);
  3. 避免在循环内疯狂 new 大量对象;循环内尽量复用对象,减少对象创建(看业务)。

五、GC 角度分析

观察 GC 日志:

复制代码
-XX:+PrintGCDetails

如果看到:YGC 频繁,每次回收后可用内存很少;频繁 Full GC,内存几乎释放不下来 → 大概率内存泄漏。 如果一次性突增大量对象直接打满堆,回收效果尚可,只是瞬时需要内存大 → 业务数据量问题。

相关推荐
香蕉大香蕉(06敬畏市场)16 小时前
高频八股 · JVM(8)
java·jvm·面试·八股·大厂实习
北冥you鱼18 小时前
Go 语言 GORM 使用 Preload:从关联查询到嵌套预加载的完整实践
开发语言·jvm·golang
兔头?19 小时前
JVM学习文档
jvm·学习
wuminyu21 小时前
JVM规范学习总结:class执行性能差异
java·linux·c语言·jvm·c++
EVEN-091321 小时前
Linux-线程控制
linux·jvm
刚入门的大一新生2 天前
Linux-线程概念
linux·jvm
eleven_4u2 天前
QPS如何计算,如何部署架构
java·linux·运维·jvm·中间件
qq_452396232 天前
第八篇:《VACUUM、自动清理与膨胀治理》
jvm·数据库·oracle
甜到心里的蛋糕2 天前
抖音评论自动回复机器人部署实践:无头 Chrome + DeepSeek + NapCat(2C2G 云主机)
java·jvm·chrome·python·抖音·deepseek
香蕉大香蕉(06敬畏市场)2 天前
高频八股 · JVM(7):方法区、元空间与字符串常量池
java·jvm·ai·博客·八股·大厂实习