
OOMJava 堆溢出java.lang.OutOfMemoryError: Java heap space现象‑Xmx 设置的最大堆内存被占满GC 反复回收回收后内存依然不够抛出堆溢出。一、定位步骤排查思路开启堆 dump发生 OOM 自动导出堆快照-XX:HeapDumpOnOutOfMemoryError -XX:HeapDumpPath/xxx/heap.hprof程序 OOM 时自动生成 hprof 文件用 MATMemory Analyzer Tool(Eclipse 开源的内存分析工具专门分析 hprof 堆转储快照文件用来排查 Java 内存泄漏、堆 OOM)分析。MAT 分析 hprof 做三件事 ① 看大对象、支配树是谁持有大量对象是谁的引用链不让对象 GC。 ② 看对象数量哪个类实例数量异常暴涨。 ③ 找泄漏点对象本应该被回收但被 GC Roots 强引用死死抱住。区分两种完全不同情况内存泄漏Memory Leak对象不再业务使用但存在强引用无法 GC内存只涨不降。内存溢出Memory Overflow业务本身就需要这么多对象内存给小了没有泄漏。二、情况 1内存泄漏最常见对象不用了还被强引用持有无法 GC。常见泄漏场景集合List/Map全局 static只 add 不 remove全局集合不断累积对象。ThreadLocal 没有 remove ()线程池线程复用ThreadLocalMap 还持有对象引用。监听器、回调注册注销失败引用没释放。内部类持有外部类引用匿名内部类捕获外部对象。缓存没有设置淘汰策略没有 LRU、过期时间无限膨胀。解决不用的对象手动清除集合元素ThreadLocal 用完必须 remove缓存增加最大容量、过期淘汰Caffeine、Guava Cache及时注销监听器回调避免长生命周期对象持有短生命周期对象。三、情况 2没有泄漏业务确实需要大量对象堆内存配置过小例子一次性查询百万数据全部加载进 List全部放到内存。MAT 看对象都是业务正常需要的没有不该存活的对象。解决思路二选一调高‑Xmx 堆内存机器物理内存允许的前提下加大堆不要一次性全加载到内存做流式处理 / 分页分批读取、游标分页不要把全量数据装入 List使用迭代器逐条处理。坑select * from table查出几十万行封装进 List直接打爆堆属于业务写法问题不是泄漏。四、代码层面临时优化手段大对象尽量方法内局部变量方法执行结束无其他引用就可以 GC大集合用完置为listnull帮助 GC Roots 解除引用更多是可读性JVM 会自动识别避免在循环内疯狂 new 大量对象循环内尽量复用对象减少对象创建看业务。五、GC 角度分析观察 GC 日志-XX:PrintGCDetails如果看到YGC 频繁每次回收后可用内存很少频繁 Full GC内存几乎释放不下来 → 大概率内存泄漏。 如果一次性突增大量对象直接打满堆回收效果尚可只是瞬时需要内存大 → 业务数据量问题。