JVM运行时内存溢出以及解决办法

JVM有哪些运行时数据区

JVM运行时数据区有程序计数器、本地方法栈+虚拟机栈、堆、元数据区、直接内存。

其中只有程序计数器不是内存溢出,其他的都有可能会产生内存溢出。

栈内存溢出

当方法的调用深度过深,可能会导致栈内存溢出。

一般是发生在递归调用的场景中,没有定义好递归基导致的栈内存溢出。

创建线程内存溢出

当内存不够,创建线程也会导致内存溢出。因为每个新的线程都需要占用一定的内存。

  • 解决办法
    查看操作系统是否有使用线程数的限制。不要随意创建线程,使用线程池来对线程进行管理,创建新的线程池时,也进行仔细的评估,是否有创建线程池的必要。

堆内存溢出

堆中加载了大量的对象,或者有超大对象,或者有很多内存泄露,就会产生堆内存溢出。

当有超大对象时,可以采用分批处理的方式解决,减少单次处理的对象的大小。

有些开发会在数据库中查询大量的数据,然后在内存中进行过滤,这种情况可以通过在查询时,通过sql进行提前过滤,避免查询大量的数据。

内存泄露,就需要避免内存泄露,比如,避免使用过多的全局变量,尽量使用局部变量,如果非要使用全局变量,就需要在使用后及时清理。在使用ThreadLocal时,里面的值如果不使用了,及时调用ThreadLocal的remove方法,避免内存泄露。

直接内存溢出

直接内存一般是用来做文件IO或者网络IO的内存,是直接向操作系统申请内存,大小限制只跟操作系统剩余内存有关,但是也可以指定直接内存大小,当指定了直接内存大小,而程序又申请了非常大的直接内存空间,没有及时清理时,就会发生直接内存溢出。

在使用ByteBuffer中的allocateDirect()的时候会用到,很多javaNIO(像netty)的框架中被封装为其他的方法,出现该问题时会抛出java.lang.OutOfMemoryError: Direct buffer memory异常。

如果你在直接或间接使用了ByteBuffer中的allocateDirect方法的时候,而不做clear的时候就会出现类似的问题。

元空间内存溢出

元空间默认大小只跟操作系统的内存大小有关,是直接向操作系统申请内存,默认没有限制,但是最好配置一下,避免整个操作系统都收到影响。

元空间存储的是类字节码文件相关的信息。当系统代码本身很多,或者引用的第三方包很多,或者通过动态代码生成了很多动态的类的字节码,就会导致元空间溢出。

所以需要我们慎用第三方包,移除不需要的第三方包,对于生成大量生成动态类的框架,做好压力测试。

垃圾回收超时内存溢出

当垃圾回收时间超过一定的比例时,就会触发这个异常,这个比例可以通过JVM启动参数进行调节。(具体的参数可以查看poe记录)

  • 解决办法
    减少对象的生命周期,避免内存泄露。

系统杀死进程内存溢出

在描述该问题之前,先熟悉一点操作系统的知识:操作系统是建立在进程的概念之上,这些进程在内核中作业,其中有一个非常特殊的进程,称为"内存杀手(Out of memory killer)"。当内核检测到系统内存不足时,OOM killer被激活,检查当前谁占用内存最多然后将该进程杀掉。

一般Out of memory:Kill process or sacrifice child错会在当可用虚拟虚拟内存(包括交换空间)消耗到让整个操作系统面临风险时,会被触发。在这种情况下,OOM Killer会选择"流氓进程"并杀死它。

虽然增加交换空间的方式可以缓解Java heap space异常,还是建议最好的方案就是升级系统内存,让java应用有足够的内存可用,就不会出现这种问题。

参考

JVM内存溢出的几种方式与解决方法

相关推荐
吴冰_hogan4 小时前
JVM(Java虚拟机)的组成部分详解
java·开发语言·jvm
东阳马生架构12 小时前
JVM实战—1.Java代码的运行原理
jvm
ThisIsClark15 小时前
【后端面试总结】深入解析进程和线程的区别
java·jvm·面试
王佑辉15 小时前
【jvm】内存泄漏与内存溢出的区别
jvm
大G哥17 小时前
深入理解.NET内存回收机制
jvm·.net
泰勒今天不想展开17 小时前
jvm接入prometheus监控
jvm·windows·prometheus
东阳马生架构2 天前
JVM简介—3.JVM的执行子系统
jvm
程序员志哥2 天前
JVM系列(十三) -常用调优工具介绍
jvm
后台技术汇2 天前
JavaAgent技术应用和原理:JVM持久化监控
jvm