OOM异常排除
什么是OOM异常
OOM(Out of Memory,内存溢出)异常是指程序在运行时超出了 JVM(Java Virtual Machine) 可用的内存空间,导致无法分配足够的内存来继续执行程序,从而引发的异常
通常,OOM 异常会发生在以下几种情况:
- 堆内存不足:JVM 堆内存不足以存储新的对象,导致 java.lang.OutOfMemoryError: Java heap space 异常。
- 栈内存不足:栈内存不足时,通常会导致 java.lang.StackOverflowError,但与 OOM 异常的根本原因类似,都是内存资源用尽。
- 直接内存不足:对于一些低级别操作,比如 NIO 中的直接内存,如果没有足够的系统内存,可能会抛出 java.lang.OutOfMemoryError: Direct buffer memory。
- 元空间内存不足:JVM 用于存放类元数据的内存区域。如果类加载过多导致元空间内存耗尽,可能会出现 java.lang.OutOfMemoryError: Metaspace 异常。
springboot中出现OOM
当出现 OOM 异常 时,Spring Boot 项目的行为取决于出现 OOM 异常的具体位置和程度,但通常会有以下几种表现:
项目无法访问接口:
OOM 异常会导致 JVM 无法继续执行任务,可能会影响项目的正常运行,尤其是当堆内存溢出时,JVM 可能会停止正常处理请求,从而导致所有接口不可用。
项目挂掉:
如果 OOM 异常非常严重,导致 JVM 无法分配任何内存或处理请求,项目可能会崩溃,Spring Boot 应用会 退出,并在日志中打印 OOM 异常信息。
通常,Spring Boot 应用会在 OOM 发生时 退出并重启(如果配置了类似 Spring Boot Actuator 或者某些自动重启工具),但这并不代表所有 OOM 都能自动恢复。最坏情况下,项目可能彻底停止。
报错信息
2025-02-12 14:25:43.456 WARN [main] o.s.boot.SpringApplication: Application run failed
java.lang.OutOfMemoryError: Java heap space
at java.util.ArrayList.<init>(ArrayList.java:131)
at java.util.ArrayList.add(ArrayList.java:402)
at com.example.service.MyService.processData(MyService.java:45)
... (其他栈信息)
可能出现OOM情况
1.一次性大量获取数据库中的数据,放入java数据结构例如hashmap中存放,这会创建大量对象,轻则项目卡顿,重则崩溃
2.高并发情况下创建大量线程池却不释放,因为线程池也是要占用内存的,所以不释放情况会逐渐占用内存空间,导致项目无法运行
3.本身java项目启动的时候堆内存空间设计得不合理
初始内存512M 最大内存2G
java -Xms512m -Xmx2g -jar your-springboot-app.jar
解决/排除方案
直接看报错信息
OOM报错的时候会打印栈信息,可能直接能找到错误位置,但是线程过多情况很难找到
堆转储方式
提前设置jvm参数
Heap Dump:如果应用发生了 OOM 异常,可以生成堆转储(heap dump)并分析内存泄漏。在路径下查看
java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/dump.hprof -jar your-springboot-app.jar
然后将获取的文件通过windows中的JVisualVM 工具查看
将文件装入JVisualVM,然后查看类信息,就可以查看到不同类占用空间的大写
这里jdk9之后移除了JVisualVM,需要自己下载VisualVM工具
可以使用jmp 打印dump(堆转储文件)
jmap -dump:format=b,file=/path/to/heapdump.hprof <pid>
找到gcroot,并在线程中显示就能看到报错信息
如何预防OOM
1.项目初期设置合理的堆内存空间,栈内存,元数据等空间
2.项目上线后实时监控内存的使用情况
对于生产环境中的应用,可以使用 JMX (Java Management Extensions) 来进行远程监控和动态调整一些 JVM 参数。通过 JMX,你可以实时查看 JVM 的内存、垃圾回收等性能指标,并进行一些操作,比如调整线程池、内存使用等。