Java OOM 常见情况

本文深入探讨了Java应用程序中出现内存溢出(OOM)的原因,包括内存分配不足和内存使用过度两大方面。阐述了三种常见OOM错误:Java堆内存溢出、永久代溢出和Java虚拟机栈溢出的具体场景与解决策略。同时,介绍了如何利用内存映射分析工具和堆dump文件进行OOM异常的定位与分析。

https://www.jianshu.com/p/9daaccbe17f4

为什么会OOM?

为什么会没有内存了呢?原因不外乎有两点:

1)分配的少了:比如虚拟机本身可使用的内存(一般通过启动时的VM参数指定)太少。

2)应用用的太多,并且用完没释放,浪费了。此时就会造成内存泄露或者内存溢出

内存泄露:申请使用完的内存没有释放,导致虚拟机不能再次使用该内存,此时这段内存就泄露了,因为申请者不用了,而又不能被虚拟机分配给别人用。

内存溢出:申请的内存超出了JVM能提供的内存大小,此时称之为溢出。

最常见的OOM情况有以下三种:

  • java.lang.OutOfMemoryError: Java heap space ------>java堆内存溢出,此种情况最常见,一般由于内存泄露或者堆的大小设置不当引起。对于内存泄露,需要通过内存监控软件查找程序中的泄露代码,而堆大小可以通过虚拟机参数-Xms,-Xmx等修改。
  • java.lang.OutOfMemoryError: PermGen space ------>java永久代溢出,即方法区溢出了,一般出现于大量Class或者jsp页面,或者采用cglib等反射机制的情况,因为上述情况会产生大量的Class信息存储于方法区。此种情况可以通过更改方法区的大小来解决,使用类似-XX:PermSize=64m -XX:MaxPermSize=256m的形式修改。另外,过多的常量尤其是字符串也会导致方法区溢出。
  • java.lang.StackOverflowError ------> 不会抛OOM error,但也是比较常见的Java内存溢出。JAVA虚拟机栈溢出,一般是由于程序中存在死循环或者深度递归调用造成的,栈大小设置太小也会出现此种溢出。可以通过虚拟机参数-Xss来设置栈的大小。
  • 解决异常
    首先通过内存映射分析工具 如 Eclipse Memory Analyzer 堆 dump出的异常堆转储进行快照解析确认内存中的对象是否是必要的  也就是先分清楚是 内存泄漏 Memory Leak 还是Memory Overflow 如果是内存泄漏 可通过工具进一步查看泄露的对象到GC Roots的引用链 就能找到泄露对象是怎么通过路径与 GC Roots 相关联导致垃圾收集器无法回收他们如果不存在泄露 就检查堆参数 -Xmx 与 -Xms 与机器物理内存对比是否还可以调大 从代码上检测 是否是某些对象的生命周期过长持有状态时间过长 尝试减少代码运行期间的内存消耗
  • 4)OOM分析--heapdump

    要dump堆的内存镜像,可以采用如下两种方式:

    设置JVM参数-XX:+HeapDumpOnOutOfMemoryError,设定当发生OOM时自动dump出堆信息。不过该方法需要JDK5以上版本。

    使用JDK自带的jmap命令。"jmap -dump:format=b,file=heap.bin <pid>"  其中pid可以通过jps获取。

    dump堆内存信息后,需要对dump出的文件进行分析,从而找到OOM的原因。常用的工具有:

    mat: eclipse memory analyzer, 基于eclipse RCP的内存分析工具。详细信息参见:http://www.eclipse.org/mat/,推荐使用。 

### Java OOM 错误原因及解决方法 Java 中的 OutOfMemoryError(简称 OOM)是常见的内存溢出错误,通常发生在 JVM 无法分配所需内存时。以下是详细的分析和解决方案: #### 1. **Java Heap Space** 当堆内存(Heap Space)没有足够空间存放新创建的对象时,会抛出 `java.lang.OutOfMemoryError: Java heap space` 错误。这种问题通常与程序中对象的生命周期管理不当有关[^3]。 - **解决方法**: - 增加堆内存大小,通过 JVM 参数 `-Xms` 和 `-Xmx` 设置初始堆大小和最大堆大小。 - 使用内存分析工具(如 VisualVM、JProfiler 或 Eclipse MAT)检查是否存在内存泄漏或大对象占用过多内存的情况。 - 确保对象在不再需要时被及时释放,避免不必要的引用。 ```bash java -Xms512m -Xmx4g MyApplication ``` #### 2. **PermGen/Metaspace** 在 JDK 8 之前,永久代(PermGen)用于存储类的元数据。如果加载了大量类且 PermGen 空间不足,会抛出 `java.lang.OutOfMemoryError: PermGen space` 错误。从 JDK 8 开始,永久代被 Metaspace 替代。 - **解决方法**: - 对于 JDK 8+,可以通过 `-XX:MaxMetaspaceSize` 参数调整 Metaspace 的大小。 - 减少动态生成类的数量,例如使用类加载器优化技术。 - 如果使用第三方框架(如 Spring、Hibernate),确保其版本兼容并优化类加载行为。 ```bash java -XX:MaxMetaspaceSize=256m MyApplication ``` #### 3. **Direct Memory** 直接内存(Direct Memory)由 JVM 外部管理,通常用于 NIO 操作。如果直接内存耗尽,会抛出 `java.lang.OutOfMemoryError: Direct buffer memory` 错误[^2]。 - **解决方法**: - 调整直接内存的最大值,通过 `-XX:MaxDirectMemorySize` 参数设置。 - 检查代码中是否正确释放了 ByteBuffer 等资源。 - 避免频繁创建和销毁大量的直接缓冲区。 ```bash java -XX:MaxDirectMemorySize=128m MyApplication ``` #### 4. **Thread Stack Size** 线程栈大小不足或线程过多时,会抛出 `java.lang.OutOfMemoryError: unable to create new native thread` 错误。这通常是由于系统资源限制或线程池配置不当引起的。 - **解决方法**: - 减少线程数量,优化线程池配置。 - 调整线程栈大小,通过 `-Xss` 参数设置。 - 检查操作系统对线程数的限制,并适当调整。 ```bash java -Xss256k MyApplication ``` #### 5. **GC Overhead Limit Exceeded** 当垃圾回收(GC)过于频繁且每次回收后仅能回收少量内存时,会抛出 `java.lang.OutOfMemoryError: GC overhead limit exceeded` 错误。这通常表明内存使用效率低下。 - **解决方法**: - 增加堆内存大小以减少 GC 频率。 - 优化代码,减少临时对象的创建。 - 调整 GC 参数,选择适合应用的垃圾回收器(如 G1、CMS)。 ```bash java -XX:+UseG1GC MyApplication ``` #### 6. **Native Memory** 本地内存(Native Memory)由 JVM 外部管理,通常用于 JNI 调用或内部数据结构。如果本地内存耗尽,会抛出 `java.lang.OutOfMemoryError: native memory exhausted` 错误[^2]。 - **解决方法**: - 检查 JNI 代码中是否存在内存泄漏。 - 优化第三方库的使用,避免不必要的内存分配。 - 监控和分析 JVM 的本地内存使用情况。 --- ### 综合案例分析 假设一个 Web 应用在高并发场景下频繁出现 OOM 错误,可能的原因包括堆内存不足、线程过多或直接内存泄漏。通过以下步骤可以定位问题: 1. 分析堆转储文件(Heap Dump),识别内存泄漏的根源。 2. 检查线程池配置,确保线程数量合理。 3. 使用监控工具(如 JConsole 或 Prometheus)观察 JVM 内存使用趋势。 --- ### OOM 的预防与调优建议 - 定期进行性能测试和压力测试,发现潜在的内存问题。 - 使用内存分析工具定期检查内存使用情况。 - 为关键业务配置告警机制,及时发现和处理 OOM 问题。 - 根据应用特点选择合适的 JVM 参数和垃圾回收器。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值