当前位置:   article > 正文

为什么会产生 java.lang.OutOfMemoryError: Java heap space 错误以及如何解决?

java.lang.outofmemoryerror: java heap space

关于 java.lang.OutOfMemoryError: Java heap space 错误,遇到的程序员可能不是很多,但是当你真的遇到的时候,你就会发现我的这篇文章对你的帮助非常的大!

引发 java.lang.OutOfMemoryError: Java heap space 错误的主要原因就是在创建新的对象时, 堆内存中的空间不足以存放新创建的对象时发生!

所以说,当有人问你:在 Java 中创建一个对象(new 一个正常的类)会不会发生异常?你应该这样回答:当堆内存中的空间不足时,可能会发生 java.lang.OutOfMemoryError: Java heap space 错误!

知道了 java.lang.OutOfMemoryError: Java heap space 错误的发生时机。我们来看看 Java 中为什么有这个异常或错误产生!

一般来说每个 Java 程序都只能使用一定量的内存,这种限制是由 JVM 的启动参数决定的。而更复杂的情况在于, Java 程序的内存主要分为两部分: 堆内存(Heap space)和 永久代(Permanent Generation,简称 Permgen):
在这里插入图片描述

堆内存和永久代

这两个区域的最大内存大小,由 JVM 启动参数 -Xmx 和 -XX:MaxPermSize 指定。如果没有明确指定,则根据平台类型(OS版本+ JVM版本)和物理内存的大小来确定。

就算机器上还存在空闲的物理内存,但只要堆内存使用量达到最大内存限制(注意,在 JVM 中如果 98% 的时间是用于 GC 且可用的 Heap size 不足 2% 的时候将抛出此异常信息),就会抛出 java.lang.OutOfMemoryError: Java heap space 错误。

产生 java.lang.OutOfMemoryError: Java heap space 错误的原因,通俗的讲就是一个人只能吃一碗米饭,吃完一碗后,你又给他乘了一碗,他说吃不下去了,吃饱了!

明白了这个原因,我们来看怎么解决它!

因为你现在饭做多了,所以让别人再吃一碗,别人也吃不下。所以,解决办法就有两种,一种就是你下次少做点饭,就只在做饭的时候就进行控制;还有一种就是一次别吃完,让它饿一下了再吃!

反映到 Java 应用程序上就是,你在程序启动的时候,把堆内存设置大一点,当然是不能超过物理内存大小的。还有一种办法就是,一些超大的,超预期的对象或数据分批来处理。例如,我定义了一个长度为 10 的数组,你就不能放置 20 个元素。你可以先放 10 个,等这 10 个用完后,再放 10 个。

另外就是,你的程序本身就有内存泄露的情况。

比如,代码中的某些错误,导致系统占用的内存越来越多。如果某个方法/某段代码存在内存泄漏的,每执行一次,就会(有更多的垃圾对象)占用更多的内存。随着运行时间的推移,泄漏的对象耗光了堆中的所有内存,那么在新创建对象等情况下就会爆发 java.lang.OutOfMemoryError: Java heap space 错误。

在启动的时候,把堆内存设置大一点的操作很简单,比如下面的配置:

JAVA_OPTS="-server -Xms800m -Xmx800m -XX:PermSize=64M -XX:MaxNewSize=256m -XX:MaxPermSize=128m -Djava.awt.headless=true "
或者也可以在 Tomcat 的 TOMCAT_HOME/bin/catalina.bat 中添加下面这句话:

set JAVA_OPTS= -Xmx1024M -Xms512M -XX:MaxPermSize=256m
除此之外,也可以在 Idea 或 Eclipse 的 Optional Java VM arguments中添加:

-Xmx1024M -Xms512M -XX:MaxPermSize=256m
如果是 SpringBoot 项目,直接执行 jar 文件,可以这样做:

java -jar -Xms258m -Xmx258m -XX:PermSize=512M -XX:MaxPermSize=512m xttblog.jar --spring.profiles.active=prod --server.port=80
上面这些设置虽然简单,但就是怕有些时候,问题的根本原因是你的程序存在内存泄露的情况。

这个时候,你扩大堆内存,只能延缓 java.lang.OutOfMemoryError: Java heap space 错误的触发时间。

所以,产生 java.lang.OutOfMemoryError: Java heap space 错误的时候,我建议你按照下面的步骤检查一边你的应用程序!

获得在生产服务器上执行堆转储(heap dump)的权限。“转储”(Dump)是堆内存的快照,稍后可以用于内存分析。这些快照中可能含有机密信息,例如密码等。所以有时候,由于企业的安全限制,要获得生产环境的堆转储并非易事。

在适当的时间执行堆转储。一般来说,内存分析需要比对多个堆转储文件,假如获取的时机不对,那就可能是一个“废”的快照。另外,每次执行堆转储,都会对JVM进行“冻结”,所以生产环境中,也不能执行太多的Dump操作,否则系统缓慢或者卡死,你的麻烦就大了。

然后用另一台机器来加载Dump文件。一般来说,如果出问题的JVM内存是8GB,那么分析 Heap Dump 的机器内存需要大于 8GB。打开转储分析软件(推荐Eclipse MAT,当然你也可以使用其他工具)。

检测快照中占用内存最大的 GC roots(具体怎么做,我后面会抽时间写文章来做教程)。这对新手或没分析过的程序员来说可能有点困难,但这也会加深你对堆内存结构以及 navigation 机制的理解。

最后就可以找出可能会分配大量对象的代码。如果对整个系统非常熟悉,那么找到的可能就会更快。

说了这么多,其实最重要的还是要加强自己的编码能力和良好的编码习惯!更多关于 JVM 的学习内容,我后面会一篇一篇的写,希望能够帮助到大家,并能得到大家的支持!

-Xms128m
表示JVM Heap(堆内存)最小尺寸128MB,初始分配
-Xmx512m
表示JVM Heap(堆内存)最大允许的尺寸256MB,按需分配。

说明:如果-Xmx不指定或者指定偏小,应用可能会导致java.lang.OutOfMemory错误,此错误来自JVM不是Throwable的,无法用try…catch捕捉。

总结:代码中用到的多线程(尤其是终身循环的那种)没有释放局部变量的连接,导致JVM(java虚拟机)不能及时清理heap(堆)中不使用了的对象导致JVM堆内存溢出;
此异常发生需要检查以下几个地方:
1、查看JVM的运行内存空间,适当的提高运行内存空间;
2、检查项目中的代码是否存在死循环,如果存在检查是否做好了资源的清理;
3、检查项目中是否存在一次性提取大量数据到内存的地方(10万数据以上);

参考:
原地址:https://www.xttblog.com/?p=3345

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/443724
推荐阅读
相关标签
  

闽ICP备14008679号