Java 常见的几种内存溢出异常的原因及解决
作者:唐宋xy 发布时间:2023-02-21 16:44:50
目录
堆内存溢出
原因:
解决方案:
栈内存溢出
原因:
解决方案:
方法区和运行时常量池内存溢出
原因:
本机直接内存溢出
原因:
解决方案:
元空间内存溢出
原因:
解决方案:
内存溢出的异常有很多,并且每种内存溢出都会有不同的异常信息和解决方式,下面会列出常见的几种内存溢出异常
堆内存溢出
java.lang.OutOfMemoryError: Java heap space
原因:
当堆内存不足,并且已经达到JVM设置的最大值,无法继续申请新的内存,存活的对象在堆内存中无法被回收,那么就会抛出该异常,表示堆内存溢出。
当一次从数据库查询大量数据,堆内存没有足够的内存可以存放大量的数据
大量的强引用对象在堆内存中存活,GC无法回收这些对象,新创建的对象在新生代无法进行分配,Full GC仍然无法进行回收
解决方案:
查看当前JVM的堆内存配置是否太小,可以考虑增加堆内存大小
JAVA_OPTS="-server -Xms1024m -Xmx1024m"
表示将堆内存的初始值和最大值都设置为1024m
-Xms设置堆内存的初始值
-Xmx设置堆内存的最大值
-Xms和-Xmx最好设置相同的内存大小,可以防止因为JVM频繁进行内存的调整影响稳定性和使用
查看代码中是否有从数据库中一次加载大量数据的情况,或者代码中有大量强引用无法进行回收
通过JVM参数:-XX:+HeapDumpOnOutOfMemoryError可以让虚拟机在出现内存溢出的时候Dump出当前的堆内存快照,便于保留快照分析
栈内存溢出
java.lang.outOfMemoryError:StackOverFlow Error
原因:
线程请求的栈深度大于虚拟机允许的最大深度,抛出StackOverflowError
虚拟机在扩展栈时无法申请到足够的内存空间,抛出OutOfMemoryError
解决方案:
检查代码是否出现深度递归的情况,或者递归的终止条件没有设置
如果是线程的栈内存空间过小,则通过-Xss设置每个线程的栈内存空间
默认的-Xss参数的大小应该是1M
栈内存是线程私有的,如果需要创建更多的线程,那么就需要将每个线程的栈内存空间减小,通过-Xss参数设置每个线程的栈内存空间
配置参数: JAVA_OPTS="-server -Xms1024m -Xmx1024m -Xss128k"
jdk8如果没有配置-Xss默认大小为512k
-Xss 设置每个线程的堆栈大小,一般默认512~1024kb,和jdk版本有关
方法区和运行时常量池内存溢出
java.lang.outOfMemoryError: PermGen space
原因:
方法区存放的是Class的相关信息,如类名、访问修饰符、常量池、字段描述、方法描述等,内存溢出的原因可能是加载的类过多导致方法区没有足够的内存
如果程序中大量使用cglib或者 * 等对目标类进行代理,那么在运行时会生成大量的代理类,如Spring、Hibernate等框架。所以生成的代理类过多导致方法区没有足够的内存
解决方案:
减少没有必要的Class加载,防止方法区内存溢出并且减少程序的编译时间
通过JVM参数设置方法区的大小,-XX:PermSize和-XX:MaxPermSize设置方法区的大小
运行时常量池是方法区的一部分,所以增加方法区的内存大小,相当于间接的增加了运行时常量池的内存大小
本机直接内存溢出
Direct buffer memory
Java 允许应用程序通过 DirectByteBuffer 直接访问堆外内存,许多高性能程序通过 DirectByteBuffer 结合内存映射文件(Memory Mapped File)实现高速 IO
原因:
DirectByteBuffer 的默认大小为 64 MB,一旦使用超出限制,就会抛出 Direct buffer memory 错误。使用NIO则可能会出现该异常
解决方案:
DirectMemory的内存大小可以通过-XX:MaxDirectMemorySize指定,如果没有设置,则默认和Java堆最大值(-Xmx)一样
元空间内存溢出
Metaspace
Jdk8 之后使用元空间(metaspace)代替永久代,元空间和永久代最大的区别是元空间的内存使用的是本地内存,而永久代使用的是JVM的内存
永久代、元空间都是方法区的实现,方法区是规范
原因:
元空间中存储的是类信息、常量池、方法描述等信息,直接使用本地内存,当本地内存不足的时候,会抛出OutOfMemoryError:Metaspace异常
解决方案:
虽然元空间的内存不是由JVM控制,不过可以通过JVM参数来设置分配的内存空间的大小-XX:MaxMetaspaceSize配置参数
来源:https://juejin.cn/post/6925787598472511501


猜你喜欢
- 网关是介于客户端和服务器端之间的中间层,所有的外部请求都会先经过 网关这一层。也就是说,API 的实现方面更多的考虑业务逻辑,而安全、性能、
- 求数组中最大的数的值:1、数组的max函数:class Program { &nb
- 本文实例讲述了Android编程之DatePicker和TimePicke简单时间监听用法。分享给大家供大家参考,具体如下:DatePick
- 代码如下import java.util.concurrent.Callable;import java.util.concurrent.E
- 一、Drools引擎简介1、基础简介Drools是一个基于java的规则引擎,开源的,可以将复杂多变的规则从硬编码中解放出来,以规则脚本的形
- 本文实例讲述了java基于JDBC连接Oracle 11g Release2的方法。分享给大家供大家参考。具体如下:Oracle 11g R
- 一.优先队列的应用优先队列在程序开发中屡见不鲜,比如操作系统在进行进程调度时一种可行的算法是使用优先队列,当一个新的进程被fork()出来后
- public void refresh() throws BeansException, IllegalStateException { &
- 本文详细分析了C#类的访问修饰符用法,分享给大家供大家参考。具体用法分析如下:默认情况下,类声明为内部的,即只有当前工程中的代码才能访问它。
- 下面将源代码贴出。 public static class ChineseToPinYin { private static readonl
- 一、SpringBoot是什么Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以
- Java常用类库Math类Math包含用于执行基本数字运算的方法,例如基本指数,对数,平方根和三角函数一、Field SummaryModi
- 这篇文章主要介绍了spring boot如何指定启动端口,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的
- 在模板文件的表达式中,可以使用“${T(全限定类名).方法名(参数)}”这种格式来调用Java类的静态方法。开发环境:IntelliJ ID
- java 多线程的几种实现方法总结1.多线程有几种实现方法?同步有几种实现方法?多线程有两种实现方法,分别是继承Thread类与实现Runn
- 本文实例为大家分享了Java实现Flappy Bird游戏的具体代码,供大家参考,具体内容如下1.首先在mainActivity.xml中放
- String replace replaceFirst repaceAll区别replace(char oldChar, char newC
- 本文实例讲述了Android编程实现分页加载ListView功能。分享给大家供大家参考,具体如下:package eoe.listview;
- 今天给大家带来一个向右滑动销毁Activity的效果,Activtiy随着手指的移动而移动,该效果在Android应用中还是比较少见的,在I
- 实践过程效果代码public partial class Form1 : Form{ public Form1()