如何处理“java.lang.OutOfMemoryError:Java堆空间”错误?

时间:2008-09-01 01:10:04

标签: java java-ee jvm out-of-memory heap-memory

我正在 Java 5 上编写客户端 Swing 应用程序(图形字体设计器)。最近,我遇到了java.lang.OutOfMemoryError: Java heap space错误,因为我对内存使用情况并不保守。用户可以打开无限数量的文件,程序将打开的对象保存在内存中。经过快速研究后,我发现Ergonomics in the 5.0 Java Virtual Machine和其他人在Windows机器上说JVM默认最大堆大小为64MB

鉴于这种情况,我应该如何处理这种约束?

我可以使用命令行选项增加最大堆大小,但这需要找出可用的RAM并编写一些启动程序或脚本。此外,增加到某些有限 max不会最终摆脱这个问题。

我可以重写一些代码来经常将对象持久化到文件系统(使用数据库是一回事)来释放内存。它可以工作,但它可能也很有效。

如果您可以向我指出上述想法或某些替代方案的详细信息,例如自动虚拟内存,动态扩展堆大小,那就太棒了。

24 个答案:

答案 0 :(得分:221)

最终,无论您在哪个平台上运行,您都可以使用有限的最大堆。在Windows 32位中,这大约是2GB(不是专门的堆,而是每个进程的总内存量)。只是碰巧Java选择使默认值更小(可能是因为程序员无法创建具有失控内存分配的程序而不会遇到此问题并且必须仔细检查他们正在做什么)。

因此,您可以采用多种方法来确定所需的内存量或减少所使用的内存量。垃圾收集语言(如Java或C#)的一个常见错误是保留对不再正在使用的对象的引用,或者在您重用时分配许多对象。只要对象具有对它们的引用,它们将继续使用堆空间,因为垃圾收集器不会删除它们。

在这种情况下,您可以使用Java内存分析器来确定程序中的哪些方法正在分配大量对象,然后确定是否有办法确保它们不再被引用,或者不在它们中分配它们。第一名。我过去使用的一个选项是“JMP”http://www.khelekore.org/jmp/

如果由于某种原因确定要分配这些对象,并且需要保留引用(取决于您正在执行的操作,可能就是这种情况),您只需要在启动时增加最大堆大小程序。但是,一旦进行了内存分析并了解了对象的分配方式,您应该更好地了解所需的内存量。

一般情况下,如果你不能保证你的程序会在一些有限的内存中运行(可能取决于输入的大小),你总会遇到这个问题。只有在耗尽所有这些后才需要查看缓存对象到磁盘等。此时你应该有一个很好的理由说“我需要Xgb内存”,你不能通过改进来解决它你的算法或内存分配模式。通常情况下,只有在大型数据集(如数据库或某些科学分析程序)上运行的算法才会出现这种情况,然后缓存和内存映射IO等技术变得有用。

答案 1 :(得分:110)

使用命令行选项-Xmx运行Java,该选项设置堆的最大大小。

See here for details

答案 2 :(得分:82)

您可以指定每个项目项目需要多少堆空间

以下是 Eclipse Helios / Juno / Kepler

右键单击

 Run As - Run Configuration - Arguments - Vm Arguments, 

然后添加此

-Xmx2048m

答案 3 :(得分:38)

增加堆大小不是“修复”它是“石膏”,100%是临时的。它会在其他地方再次崩溃。要避免这些问题,请编写高性能代码。

  1. 尽可能使用局部变量。
  2. 确保选择正确的对象(EX:String,StringBuffer和StringBuilder之间的选择)
  3. 为您的程序使用一个好的代码系统(EX:使用静态变量VS非静态变量)
  4. 可能对您的代码有效的其他内容。
  5. 尝试使用multy THREADING移动

答案 4 :(得分:31)

大警告----在我的办公室,我们发现(在某些Windows机器上)我们无法为Java堆分配超过512米。原来这是因为卡巴斯基反病毒产品安装在其中一些机器上。在卸载该AV产品后,我们发现我们可以分配至少1.6gb,即-Xmx1600m(m是强制性的,否则它将导致另一个错误“太小的初始堆”)。

不知道其他AV产品是否会发生这种情况,但可能会发生这种情况,因为AV程序在每个地址空间都保留了一小块内存,从而阻止了单个非常大的分配。

答案 5 :(得分:20)

VM参数在eclipse中对我有用。如果您使用的是eclipse版本3.4,请执行以下操作

转到Run --> Run Configurations -->然后选择maven build下的项目 - >然后选择标签“JRE” - >然后输入-Xmx1024m

或者您可以Run --> Run Configurations --> select the "JRE" tab -->然后输入 - Xmx1024m

这应该增加所有构建/项目的内存堆。以上内存大小为1 GB。您可以优化您想要的方式。

答案 6 :(得分:16)

是的,使用-Xmx,您可以为JVM配置更多内存。 确保不泄漏或浪费记忆。进行堆转储并使用the Eclipse Memory Analyzer分析内存消耗。

答案 7 :(得分:13)

我想添加来自oracle trouble shooting文章的推荐。

thread thread_name中的异常: java.lang.OutOfMemoryError:Java堆空间

  

详细消息Java堆空间表示无法在Java堆中分配对象。此错误不一定意味着内存泄漏

可能的原因:

  1. 简单配置问题,其中指定的堆大小不足以满足应用程序。

  2. 应用程序无意中持有对象的引用,这可以防止对象被垃圾回收。

  3. 过度使用终结者

  4.   

    此错误的另一个潜在来源是过度使用终结器的应用程序。如果一个类有一个finalize方法,那么那个类型的对象在垃圾收集时没有回收它们的空间

    垃圾收集之后,对象排队等待 finalization ,这将在以后发生。 终结器由为终结队列提供服务的守护程序线程执行。如果终结器线程无法跟上最终化队列,则Java堆可能会填满,并且会抛出此类 OutOfMemoryError 异常。

    可能导致这种情况的一种情况是,当应用程序创建高优先级线程时会导致 finalization 队列以比速率更快的速率增加终结者线程正在为该队列提供服务。

答案 8 :(得分:8)

按照以下步骤操作:

  1. 从tomcat / bin打开catalina.sh

  2. 将JAVA_OPTS更改为

    JAVA_OPTS="-Djava.awt.headless=true -Dfile.encoding=UTF-8 -server -Xms1536m 
    -Xmx1536m -XX:NewSize=256m -XX:MaxNewSize=256m -XX:PermSize=256m 
    -XX:MaxPermSize=256m -XX:+DisableExplicitGC"
    
  3. 重新启动tomcat

答案 9 :(得分:7)

我遇到了java堆大小相同的问题。

如果您使用的是java 5(1.5),我有两个解决方案。

  1. 只需安装jdk1.6并转到eclipse的首选项并设置jav1 1.6的jre路径。

  2. 检查你的VM参数,让它成为它的任何东西。 只需在VM参数中的所有参数下面添加一行作为 -Xms512m -Xmx512m -XX:MaxPermSize = ... m(192m)。

  3. 我认为它会起作用......

答案 10 :(得分:7)

在java中解决OutOfMemoryError的简单方法是使用JVM选项-Xmx512M来增加最大堆大小,这将立即解决您的OutOfMemoryError。当我在构建项目时在Eclipse,Maven或ANT中获得OutOfMemoryError时,这是我的首选解决方案,因为根据项目的大小,您可以轻松地耗尽内存。

以下是增加JVM最大堆大小的示例,如果在java应用程序中设置堆大小,最好将-Xmx保持为-Xms比例为1:1或1:1.5。

export JVM_ARGS="-Xms1024m -Xmx1024m"

Reference Link

答案 11 :(得分:7)

我在其他地方读到你可以尝试 - 捕获java.lang.OutOfMemoryError并在catch块上,你可以释放你知道可能使用大量内存,关闭连接等所有资源,然后执行{{然后重新尝试你要做的事情。

另一种方式是,但我不知道这是否有效,但我目前正在测试它是否适用于我的应用程序。

想法是通过调用System.gc()来进行垃圾收集,这已知会增加可用内存。执行内存吞噬代码后,您可以继续检查。

System.gc()

答案 12 :(得分:7)

如果您需要在运行时监视内存使用情况,java.lang.management程序包提供MBeans可用于监视VM中的内存池(例如,伊甸园空间,终身生成等),以及垃圾收集行为。

这些MBean报告的可用堆空间会因GC行为而有很大差异,特别是如果您的应用程序生成了很多后来GC编辑的对象。一种可能的方法是在每个完整GC之后监视可用堆空间,您可以通过持久化对象来决定是否释放内存。

最终,您最好的选择是尽可能地限制您的记忆保留,同时表现仍然可以接受。正如先前的评论所指出的那样,内存总是有限的,但你的应用应该有一个处理内存耗尽的策略。

答案 13 :(得分:7)

默认情况下,开发JVM使用小尺寸和小配置来处理其他与性能相关的功能。但对于生产,您可以调整,例如(此外,它可以存在Application Server特定的配置) - > (如果仍然没有足够的内存来满足请求并且堆已经达到最大大小,则会发生OutOfMemoryError)

-Xms<size>        set initial Java heap size
-Xmx<size>        set maximum Java heap size
-Xss<size>        set java thread stack size

-XX:ParallelGCThreads=8
-XX:+CMSClassUnloadingEnabled
-XX:InitiatingHeapOccupancyPercent=70
-XX:+UnlockDiagnosticVMOptions
-XX:+UseConcMarkSweepGC
-Xms512m
-Xmx8192m
-XX:MaxPermSize=256m (in java 8 optional)

例如:在Linux平台上用于生产模式的首选设置。

以这种方式下载和配置服务器http://www.ehowstuff.com/how-to-install-and-setup-apache-tomcat-8-on-centos-7-1-rhel-7/

1.在文件夹/ opt / tomcat / bin /

上创建setenv.sh文件
   touch /opt/tomcat/bin/setenv.sh

2.打开并写下此参数以设置优选模式。

nano  /opt/tomcat/bin/setenv.sh 

export CATALINA_OPTS="$CATALINA_OPTS -XX:ParallelGCThreads=8"
export CATALINA_OPTS="$CATALINA_OPTS -XX:+CMSClassUnloadingEnabled"
export CATALINA_OPTS="$CATALINA_OPTS -XX:InitiatingHeapOccupancyPercent=70"
export CATALINA_OPTS="$CATALINA_OPTS -XX:+UnlockDiagnosticVMOptions"
export CATALINA_OPTS="$CATALINA_OPTS -XX:+UseConcMarkSweepGC"
export CATALINA_OPTS="$CATALINA_OPTS -Xms512m"
export CATALINA_OPTS="$CATALINA_OPTS -Xmx8192m"
export CATALINA_OPTS="$CATALINA_OPTS -XX:MaxMetaspaceSize=256M"

3。service tomcat restart

  

请注意,JVM使用的内存多于堆。例如   Java方法,线程堆栈和本机句柄在内存中分配   与堆分开,以及JVM内部数据结构。

答案 14 :(得分:5)

请注意,如果在部署情况下需要这个,请考虑使用Java WebStart(带有“ondisk”版本,而不是网络版本 - 可能在Java 6u10及更高版本中),因为它允许您指定JVM的各种参数以跨平台的方式。

否则,您将需要一个特定于操作系统的启动器来设置您需要的参数。

答案 15 :(得分:1)

如果继续分配&amp;保持对象的引用,你将填满你拥有的任何内存。

一个选项是关闭透明文件&amp;当他们切换标签时打开(你只保留指向文件的指针,当用户切换标签时,你关闭并清理所有对象......它会使文件变慢......但......),并且可能只在内存中保留3或4个文件。

您应该做的其他事情是,当用户打开文件,加载它并拦截任何OutOfMemoryError,然后(因为无法打开文件)关闭该文件,清理其对象并警告用户他应关闭未使用的文件。

你想要动态扩展虚拟内存并不能解决问题,因为机器的资源有限,所以你应该小心谨慎。处理内存问题(或至少,小心它们)。

我见过的有关内存泄漏的一些提示是:

- &GT;请记住,如果你把一些东西放入一个集合中然后忘记它,你仍然有一个强烈的参考,所以取消集合,清理它或用它做一些事情......如果不是你会发现内存泄漏困难找到。

- &GT;也许,使用带有弱引用的集合(weakhashmap ...)可以帮助解决内存问题,但是必须要小心它,因为您可能会发现已经收集了您要查找的对象。

- &GT;我发现的另一个想法是开发一个存储在最少使用和透明加载的数据库对象上的持久集合。这可能是最好的方法......

答案 16 :(得分:1)

如果在Wildfly 8和JDK1.8中发生此问题,那么我们需要指定MaxMetaSpace设置而不是PermGen设置。

例如,我们需要在wildfly的setenv.sh文件中添加以下配置。 JAVA_OPTS="$JAVA_OPTS -XX:MaxMetaspaceSize=256M"

有关详细信息,请查看Wildfly Heap Issue

答案 17 :(得分:1)

关于netbeans,您可以设置最大堆大小来解决问题。

转到'运行',然后 - &gt; '设置项目配置' - &gt; '自定义' - &gt;弹出窗口的“运行” - &gt; 'VM Option' - &gt;填写'-Xms2048m -Xmx2048m'。

答案 18 :(得分:1)

如果此错误在您的 junit 测试执行后立即发生,那么您应该执行 Build -> Rebuild Project

答案 19 :(得分:0)

如果其他所有操作均失败,则除了增加最大堆大小外,还尝试增加交换大小。对于Linux,到目前为止,相关说明可以在https://linuxize.com/post/create-a-linux-swap-file/中找到。

例如,这可以为您提供帮助在嵌入式平台上编译大型内容。

答案 20 :(得分:0)

如果启动Eclipse Birt时收到此错误 1-您将进入eclipse配置文件 2-您必须打开eclipse.init 3-修改了RAM内存,您可以增加它,我举个例子。

我以前的信息是: -Xmx128m -XX:MaxPermSize = 128m

我进行的新修改:

-Xmx512m -XX:MaxPermSize = 512m

此修改将允许我在浏览器中启动报表时解析Java堆空间。

谢谢

答案 21 :(得分:0)

在android studio中,在gradle.properties (Global Properties)的末尾添加/更改此行:

...
org.gradle.jvmargs=-XX\:MaxHeapSize\=1024m -Xmx1024m 

如果它不起作用,则可以使用大于1024的堆大小重试。

答案 22 :(得分:0)

安卓工作室

File -> Invalidate Caches and Restart 为我解决了这个问题:)

答案 23 :(得分:0)

当您的数据库连接池已满时,也会出现 Java OOM 堆空间问题。

我遇到这个问题是因为我的 Hikari 连接池(升级到 Spring boot 2.4.* 时)已满,无法再提供连接(所有活动连接仍在等待从数据库获取结果)。

问题是我们在 JPA 存储库中的一些原生查询包含 ORDER BY ?#{#pageable},升级后需要很长时间才能获得结果。

从 JPA 存储库中的所有本机查询中删除了 ORDER BY ?#{#pageable},并且解决了 OOM 堆空间问题以及连接池问题。