outofmemoryerror 也就是 OOM 内存溢出错误,是 Java 程序运行时抛出的致命错误,含义是 JVM 堆内存已经耗尽,没有多余内存继续创建新对象,同时垃圾回收 GC 也无法回收出可用空间,程序会直接终止,这个报错不是单纯把内存调大就一定能根治,很多时候是代码存在内存泄漏 大对象一次性加载 集合无限堆积 未关闭流连接等问题,盲目加大堆内存只会延后报错,最终还是会崩溃,解决思路要分成临时扩容 代码排查 参数调优 日志定位这几个方向,区分是堆溢出 元空间溢出 直接内存溢出不同类型,不同类型的 outofmemoryerror 处理方式差别很大,开发和运维人员需要先根据报错堆栈判断 OOM 类别,再执行对应的修复动作。
OOM 常见类型对照表
| 类型 | 报错关键字 | 触发核心原因 |
|---|---|---|
| Java 堆溢出 | Java heap space | 堆内对象过多,内存泄漏,一次性加载超大数据 |
| 元空间溢出 | Metaspace | 动态类加载过多,类加载器泄漏,比如 cglib 动态生成类 |
| 直接内存溢出 | Direct buffer memory | NIO 堆外内存没有释放,Netty 等框架容易出现 |
| GC overhead limit exceeded | GC overhead limit exceeded | GC 占用大量时间但是回收内存很少,属于堆溢出衍生报错 |
第一步 识别报错类型
拿到报错堆栈,优先看冒号后面的描述,Java heap space 是最常见堆内存溢出,Metaspace 对应元空间,Direct buffer memory 对应堆外直接内存,确认类型之后再选择调优参数,不要全部都修改 Xmx 堆最大值。
第二步 JVM 参数临时扩容方案
启动脚本里面修改 JVM 启动参数,这是最快临时缓解办法
- Xms 设置堆初始内存
- Xmx 设置堆最大内存,堆溢出 Java heap space 就调大这个参数
- XX:MetaspaceSize 元空间初始大小
- XX:MaxMetaspaceSize 元空间溢出时调大这个参数
示例 java Xms1g Xmx4g jar 应用.jar
注意 32 位 JVM 存在内存上限,超过之后必须切换 64 位 JDK,同时要保证服务器物理内存足够,不能设置 Xmx 超过机器可用内存,否则会触发操作系统层面 swap,性能急剧下降。
第三步 开启 OOM dump 日志定位根因
为了找到到底是哪个对象占用内存,启动参数增加 dump 配置,程序发生 outofmemoryerror 的时候自动生成堆转储文件
- XX:+HeapDumpOnOutOfMemoryError
- XX:HeapDumpPath 指定 dump 文件保存路径
生成 dump 文件之后,使用 MAT JProfiler VisualVM 这类内存分析工具打开,查看占用内存最大的对象,追踪对象引用链,定位内存泄漏代码位置。
第四步 代码层面根治修复
- 大文件大数据集不要一次性全部读入内存,改成分批读取 流式处理
- 集合容器及时清理,静态集合长期持有对象引用造成内存泄漏
- 数据库连接 文件流 网络流使用完关闭,优先使用 try with resource 自动释放
- 缓存设置过期策略和最大容量,防止缓存无限增长
- 排查动态代理 类加载器,避免重复加载大量 class 导致元空间持续上涨
第五步 框架场景专项处理
Spring Netty Flink 这类框架 OOM 比较高频,Netty 重点检查堆外内存参数 MaxDirectMemorySize,大数据批处理任务要调整任务堆内存,避免单任务一次性加载全量数据。
【常见问题】
问题 1 outofmemoryerror 是不是只要调大 Xmx 就能彻底解决
回答 1 outofmemoryerror 不是调大 Xmx 就可以彻底解决,如果根源是代码内存泄漏,调大 Xmx 只是推迟 outofmemoryerror 报错时间,后续依然会再次触发 OOM,必须结合 dump 分析修复代码。
问题 2 outofmemoryerror 里面 Metaspace 报错和 Java heap space 处理一样吗
回答 1 outofmemoryerror 里面 Metaspace 报错和 Java heap space 处理不一样,Java heap space 调整 Xmx 堆参数,Metaspace 是类元数据溢出,需要调整 MaxMetaspaceSize,并且排查动态类加载泄漏。
问题 3 outofmemoryerror 生成的 dump 文件有什么作用
回答 1 outofmemoryerror 触发自动生成的 dump 堆转储文件,可以使用 MAT 等工具分析对象占用,找到造成 outofmemoryerror 的大对象和引用链,是定位内存泄漏最核心的资料。
【免责申明】
本文属于 Java OOM 通用技术科普,不同业务框架 中间件版本 OOM 根因存在差异,JVM 参数调优需要结合服务器硬件和业务负载验证,生产环境修改参数前建议先在测试环境验证。


