1篇文章搞清楚8种JVM内存溢出(OOM)的原因和解决方法

简介: 8种JVM内存溢出(OOM)的原因和解决方法

前言

撸Java的同学,多多少少会碰到内存溢出(OOM)的场景,但造成OOM的原因却是多种多样。

堆溢出

这种场景最为常见,报错信息:

java.lang.OutOfMemoryError: Java heap space

原因
1、代码中可能存在大对象分配
2、可能存在内存泄露,导致在多次GC之后,还是无法找到一块足够大的内存容纳当前对象。
解决方法
1、检查是否存在大对象的分配,最有可能的是大数组分配
2、通过jmap命令,把堆内存dump下来,使用mat工具分析一下,检查是否存在内存泄露的问题
3、如果没有找到明显的内存泄露,使用 -Xmx 加大堆内存
4、还有一点容易被忽略,检查是否有大量的自定义的 Finalizable 对象,也有可能是框架内部提供的,考虑其存在的必要性

永久代/元空间溢出

报错信息:

java.lang.OutOfMemoryError: PermGen spacejava.lang.OutOfMemoryError: Metaspace

原因
永久代是 HotSot 虚拟机对方法区的具体实现,存放了被虚拟机加载的类信息、常量、静态变量、JIT编译后的代码等。
JDK8后,元空间替换了永久代,元空间使用的是本地内存,还有其它细节变化:
字符串常量由永久代转移到堆中
和永久代相关的JVM参数已移除
可能原因有如下几种:
1、在Java7之前,频繁的错误使用String.intern()方法
2、运行期间生成了大量的代理类,导致方法区被撑爆,无法卸载
3、应用长时间运行,没有重启
没有重启 JVM 进程一般发生在调试时,如下面 tomcat 官网的一个 FAQ:

Why does the memory usage increase when I redeploy a web application? That is because your web application has a memory leak. A common issue are “PermGen” memory leaks. They happen because the Classloader (and the Class objects it loaded) cannot be recycled unless some requirements are met (). They are stored in the permanent heap generation by the JVM, and when you redeploy a new class loader is created, which loads another copy of all these classes. This can cause OufOfMemoryErrors eventually. (*) The requirement is that all classes loaded by this classloader should be able to be gc’ed at the same time.

解决方法
因为该OOM原因比较简单,解决方法有如下几种:
1、检查是否永久代空间或者元空间设置的过小
2、检查代码中是否存在大量的反射操作
3、dump之后通过mat检查是否存在大量由于反射生成的代理类
4、放大招,重启JVM
欢迎大家关注我的公种浩【程序员追风】,文章都会在里面更新,整理的资料也会放在里面。
image

GC overhead limit exceeded

这个异常比较的罕见,报错信息:

java.lang.OutOfMemoryError:GC overhead limit exceeded

原因
这个是JDK6新加的错误类型,一般都是堆太小导致的。Sun 官方对此的定义:超过98%的时间用来做GC并且回收了不到2%的堆内存时会抛出此异常。
解决方法
1、检查项目中是否有大量的死循环或有使用大内存的代码,优化代码。
2、添加参数 -XX:-UseGCOverheadLimit 禁用这个检查,其实这个参数解决不了内存问题,只是把错误的信息延后,最终出现 java.lang.OutOfMemoryError: Java heap space。
3、dump内存,检查是否存在内存泄露,如果没有,加大内存。

方法栈溢出

报错信息:

java.lang.OutOfMemoryError : unable to create new native Thread

原因
出现这种异常,基本上都是创建的了大量的线程导致的,以前碰到过一次,通过jstack出来一共8000多个线程。
解决方法
1、通过 -Xss 降低的每个线程栈大小的容量 2、线程总数也受到系统空闲内存和操作系统的限制,检查是否该系统下有此限制:
/proc/sys/kernel/pid_max
/proc/sys/kernel/thread-max
maxuserprocess(ulimit -u)
/proc/sys/vm/maxmapcount

非常规溢出

下面这些OOM异常,可能大部分的同学都没有碰到过,但还是需要了解一下
分配超大数组
报错信息 :

java.lang.OutOfMemoryError: Requested array size exceeds VM limit

这种情况一般是由于不合理的数组分配请求导致的,在为数组分配内存之前,JVM 会执行一项检查。要分配的数组在该平台是否可以寻址(addressable),如果不能寻址(addressable)就会抛出这个错误。
解决方法就是检查你的代码中是否有创建超大数组的地方。

swap溢出

报错信息 :

java.lang.OutOfMemoryError: Out of swap space

这种情况一般是操作系统导致的,可能的原因有:
1、swap 分区大小分配不足;
2、其他进程消耗了所有的内存。
解决方案:
1、其它服务进程可以选择性的拆分出去
2、加大swap分区大小,或者加大机器内存大小

本地方法溢出

报错信息 :

java.lang.OutOfMemoryError: stack_trace_with_native_method

本地方法在运行时出现了内存分配失败,和之前的方法栈溢出不同,方法栈溢出发生在 JVM 代码层面,而本地方法溢出发生在JNI代码或本地方法处。
这个异常出现的概率极低,只能通过操作系统本地工具进行诊断,难度有点大,还是放弃为妙。

最后

欢迎大家一起交流,喜欢文章记得关注我点个赞哟,感谢支持!

相关文章
|
5月前
|
Arthas 存储 算法
深入理解JVM,包含字节码文件,内存结构,垃圾回收,类的声明周期,类加载器
JVM全称是Java Virtual Machine-Java虚拟机JVM作用:本质上是一个运行在计算机上的程序,职责是运行Java字节码文件,编译为机器码交由计算机运行类的生命周期概述:类的生命周期描述了一个类加载,使用,卸载的整个过类的生命周期阶段:类的声明周期主要分为五个阶段:加载->连接->初始化->使用->卸载,其中连接中分为三个小阶段验证->准备->解析类加载器的定义:JVM提供类加载器给Java程序去获取类和接口字节码数据类加载器的作用:类加载器接受字节码文件。
470 55
|
6月前
|
Arthas 监控 Java
Arthas memory(查看 JVM 内存信息)
Arthas memory(查看 JVM 内存信息)
446 6
|
9月前
|
存储 设计模式 监控
快速定位并优化CPU 与 JVM 内存性能瓶颈
本文介绍了 Java 应用常见的 CPU & JVM 内存热点原因及优化思路。
921 166
|
7月前
|
存储 缓存 算法
JVM简介—1.Java内存区域
本文详细介绍了Java虚拟机运行时数据区的各个方面,包括其定义、类型(如程序计数器、Java虚拟机栈、本地方法栈、Java堆、方法区和直接内存)及其作用。文中还探讨了各版本内存区域的变化、直接内存的使用、从线程角度分析Java内存区域、堆与栈的区别、对象创建步骤、对象内存布局及访问定位,并通过实例说明了常见内存溢出问题的原因和表现形式。这些内容帮助开发者深入理解Java内存管理机制,优化应用程序性能并解决潜在的内存问题。
321 29
JVM简介—1.Java内存区域
|
7月前
|
缓存 监控 算法
JVM简介—2.垃圾回收器和内存分配策略
本文介绍了Java垃圾回收机制的多个方面,包括垃圾回收概述、对象存活判断、引用类型介绍、垃圾收集算法、垃圾收集器设计、具体垃圾回收器详情、Stop The World现象、内存分配与回收策略、新生代配置演示、内存泄漏和溢出问题以及JDK提供的相关工具。
JVM简介—2.垃圾回收器和内存分配策略
|
7月前
|
存储 设计模式 监控
如何快速定位并优化CPU 与 JVM 内存性能瓶颈?
如何快速定位并优化CPU 与 JVM 内存性能瓶颈?
168 0
如何快速定位并优化CPU 与 JVM 内存性能瓶颈?
|
8月前
|
存储 算法 Java
JVM: 内存、类与垃圾
分代收集算法将内存分为新生代和老年代,分别使用不同的垃圾回收算法。新生代对象使用复制算法,老年代对象使用标记-清除或标记-整理算法。
103 6
|
10月前
|
存储 Java 程序员
【JVM】——JVM运行机制、类加载机制、内存划分
JVM运行机制,堆栈,程序计数器,元数据区,JVM加载机制,双亲委派模型
236 10
|
10月前
|
存储 监控 算法
深入探索Java虚拟机(JVM)的内存管理机制
本文旨在为读者提供对Java虚拟机(JVM)内存管理机制的深入理解。通过详细解析JVM的内存结构、垃圾回收算法以及性能优化策略,本文不仅揭示了Java程序高效运行背后的原理,还为开发者提供了优化应用程序性能的实用技巧。不同于常规摘要仅概述文章大意,本文摘要将简要介绍JVM内存管理的关键点,为读者提供一个清晰的学习路线图。
|
3月前
|
存储
阿里云轻量应用服务器收费标准价格表:200Mbps带宽、CPU内存及存储配置详解
阿里云香港轻量应用服务器,200Mbps带宽,免备案,支持多IP及国际线路,月租25元起,年付享8.5折优惠,适用于网站、应用等多种场景。
833 0

热门文章

最新文章