JVM——OOM异常

张开发
2026/4/5 2:02:44 15 分钟阅读

分享文章

JVM——OOM异常
目录OOM异常***你听过直接内存吗什么是 OOM常见 OOM 类型及产生原因OOM 触发完整场景OOM 问题定位步骤OOM 解决与优化方案OOM异常***你听过直接内存吗直接内存Direct Memory并不是虚拟机运行时数据区的一部分也不是Java虚拟机中定义的内存区域。但是这部分内存也被频繁地使用而且也可能导致 OutOfMemoryError 异常出现。简记直接内存又称堆外内存是虚拟机内存之外的内存直接内存不会进行垃圾回收当我们使用的时候要手动进行回收不然就会导致内存泄漏。什么是 OOM全称java.lang.OutOfMemoryError简称OOM意为「内存溢出」本质JVM 无法申请到足够内存来存放新对象 / 数据抛出的致命错误范围不只是「堆溢出」还包括方法区溢出、直接内存溢出等多种类型。常见 OOM 类型及产生原因1. 堆溢出最常见错误信息java.lang.OutOfMemoryError: Java heap space核心原因老年代满了执行 Full GC 后仍无法容纳新对象 / 晋升对象大对象分配失败超大对象无法放入 Eden 区也无法放入老年代整体堆内存耗尽新生代 老年代总内存达到-Xmx上限无法再扩容内存泄漏大量对象被长期引用如缓存未清理、静态集合无限增长无法被 GC 回收。2. 方法区溢出错误信息JDK7 及之前java.lang.OutOfMemoryError: PermGen spaceJDK8 及之后java.lang.OutOfMemoryError: Meta space核心原因方法区永久代 / 元空间被类元数据占满典型场景加载大量第三方 Jar 包如 Tomcat 部署过多应用框架动态生成大量类如 MyBatis Mapper、AOP 代理、Feign 接口、CGLIB 动态子类大量动态反射生成类导致类加载器无法卸载元数据持续累积。3. 直接内存溢出错误信息java.lang.OutOfMemoryError: Direct Memory space核心原因NIO 等框架使用的直接内存Direct ByteBuffer超过-XX:MaxDirectMemorySize限制未被及时释放。OOM 触发完整场景触发阶段OOM 类型核心原因Minor GC 阶段Java heap space1. Minor GC 前老年代空间担保失败Full GC 后仍无足够空间2. 新生代 老年代整体内存耗尽无法分配新对象Full GC 阶段Java heap spaceFull GC 后堆内存仍无法容纳新对象方法区阶段PermGen/Meta space方法区被类元数据占满Full GC 无法释放足够空间直接内存阶段Direct Memory space直接内存使用超过上限未及时释放OOM 问题定位步骤第一步生成堆转储文件Heap Dump在 JVM 启动参数中添加-Xms30m -Xmx30m -XX:HeapDumpOnOutOfMemoryError作用OOM 发生时自动生成.hprof堆快照文件记录当时内存状态-Xms/-Xmx设置堆大小便于复现问题-XX:HeapDumpOnOutOfMemoryError触发 OOM 时生成 dump 文件。第二步分析堆转储文件使用工具打开.hprof文件IDEA 直接打开JDK 自带工具jhat、jvisualvm专业工具Eclipse MAT、YourKit、VisualVM 等。第三步定位问题根源收集错误信息查看日志确认 OOM 类型堆 / 方法区 / 直接内存分析堆快照查看内存占用最高的对象 / 数据结构检查是否存在内存泄漏长时间存活的对象、未清理的缓存、静态集合无限增长确认是否存在大对象如超大数组、集合检查内存使用趋势是否存在持续的内存增长未被 GC 回收定位代码位置找到创建大量对象 / 动态类的业务代码或框架配置。OOM 解决与优化方案1. 堆溢出优化增加堆内存调大-Xmx参数治标需配合代码优化修复内存泄漏清理无用对象引用如手动清空集合、关闭资源合理设计缓存设置过期时间、限制缓存大小避免静态集合无限存储对象减少大对象拆分超大数组 / 集合避免一次性加载全量数据优化对象创建复用对象如对象池减少频繁创建 / 销毁。2. 方法区溢出优化增加元空间内存JDK8 调大-XX:MaxMetaspaceSize减少动态类生成避免过度使用动态代理如 AOP、MyBatis Mapper优化框架配置限制动态类数量及时卸载无用类确保类加载器可被 GC 回收精简依赖移除不必要的第三方 Jar 包减少类加载数量。3. 直接内存溢出优化限制直接内存大小设置-XX:MaxDirectMemorySize及时释放直接内存手动调用DirectBuffer.cleaner().clean()释放避免过度使用 NIO 直接缓冲区改用堆内缓冲区。4. 通用优化监控与预警使用 JMX、Prometheus 等工具监控内存使用趋势性能测试压测场景下验证内存稳定性提前发现问题代码规范避免无限增长的集合、长生命周期的局部变量、未关闭的资源。

更多文章