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

Eug*_*ota 395 java jvm heap-memory out-of-memory java-ee

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

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

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

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

如果您可以向我指出上述想法的细节或某些替代方案,如自动虚拟内存,动态扩展堆大小,这将是很好的.

Ben*_*lds 231

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

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

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

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

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

  • OpenJDK和OracleJDK捆绑了profiler - jvisualvm.如果您想要更多便利,我建议使用商业版. (2认同)
  • 使用关闭未使用的对象和数组,例如 resultsSet.close(); 文件输出流.close(); fileOutputStream.flush(); ,我使用 resultsSet.close() 并且工作得非常神奇。 (2认同)

Dav*_*ebb 119

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

详情请见此处..

  • 如何永远设置此参数?原因我正在使用“ gradlew assemble”命令。 (2认同)
  • 运行->运行配置->单击参数->内部VM参数类型-Xms1g -Xmx2g (2认同)

all*_*kim 84

您可以为每个项目指定项目所需的堆空间

以下是Eclipse Helios/Juno/Kepler:

鼠标右键单击

 Run As - Run Configuration - Arguments - Vm Arguments, 
Run Code Online (Sandbox Code Playgroud)

然后加上这个

-Xmx2048m
Run Code Online (Sandbox Code Playgroud)


Pea*_*Gen 42

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

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

  • 我不同意。您最初需要将其设置为某个值。如果事实证明它不够充分,并不一定意味着您的应用程序很糟糕。也许你太乐观了。在这种情况下,将其设置为更高的值是一个有效的解决方案。 (9认同)
  • @Ash:是的,解决核心问题而不是寻找膏药。 (2认同)

Dav*_*vid 31

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

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


小智 22

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

Run --> Run Configurations -->然后选择Maven构建下的项目- >然后选择选项卡"JRE" - >然后输入-Xmx1024m.

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

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


koh*_*erm 17

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

  • JVMJ9VM007E 命令行选项无法识别:-Xmx 无法创建 Java 虚拟机。投反对票 (3认同)

Rav*_*abu 16

我想添加来自oracle 故障排除文章的建议

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

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

可能的原因:

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

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

  3. 过度使用终结器.

对于过度使用终结器的应用程序,会出现此错误的另一个潜在来源.如果类具有finalize方法,则该类型的对象在垃圾收集时不会回收它们的空间

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

可能导致这种情况的一种情况是,应用程序创建高优先级线程,导致最终化队列以比终结器线程为该队列服务的速率更快的速率增加.


Cod*_*Era 10

在android/gradle.properties中添加以下代码:

org.gradle.jvmargs=-Xmx4096m -XX:MaxPermSize=4096m -XX:+HeapDumpOnOutOfMemoryError
org.gradle.daemon=true
org.gradle.parallel=true
org.gradle.configureondemand=true
Run Code Online (Sandbox Code Playgroud)


小智 10

如果你来这里是从 REACT NATIVE 搜索这个问题。

那我想你应该这样做

cd android/ && ./gradlew clean && cd ..
Run Code Online (Sandbox Code Playgroud)


Pra*_*att 9

请遵循以下步骤:

  1. 从tomcat/bin打开catalina.sh.

  2. Chnage 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"
    
    Run Code Online (Sandbox Code Playgroud)
  3. 重启你的tomcat


Tal*_*bar 9

将此行添加到您的 gradle.properties 文件中

org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
Run Code Online (Sandbox Code Playgroud)

它应该有效。您可以相应地更改 MaxPermSize 来解决堆问题


Lei*_*igh 7

如果需要在运行时监视内存使用情况,则java.lang.management包提供可用于监视VM中内存池的MBean(例如,eden空间,tenured generation等)以及垃圾收集行为.

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

最终,您最好的选择是尽可能地限制记忆力,同时保持性能可接受.正如先前的评论所指出的,内存总是有限的,但你的应用应该有一个处理内存耗尽的策略.


mwa*_*ngi 7

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

另一种方式是,虽然,我不知道这是否可行,但我目前正在测试它是否适用于我的应用程序.

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

//Mimimum acceptable free memory you think your app needs
long minRunningMemory = (1024*1024);

Runtime runtime = Runtime.getRuntime();

if(runtime.freeMemory()<minRunningMemory)
 System.gc();
Run Code Online (Sandbox Code Playgroud)

  • 一般来说,我认为JVM更喜欢垃圾收集(GC),而不是抛出OutOfMemoryError.在OutOfMemoryError之后显式调用System.gc()可能对某些VM /配置有帮助,但我不希望它在一般情况下工作得很好.但是,删除不必要的对象引用肯定会对几乎所有情况都有帮助. (6认同)
  • @mwangi直接从代码调用System.gc()通常是一个坏主意.这只是对JVM的**建议**应该执行GC,但绝对不能保证**它将被执行. (5认同)

小智 7

我遇到了java堆大小相同的问题.如果您使用的是java 5(1.5),我有两个解决方案.

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

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

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


小智 7

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

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

export JVM_ARGS="-Xms1024m -Xmx1024m"

参考链接


Mus*_*usa 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)
Run Code Online (Sandbox Code Playgroud)

例如:在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
Run Code Online (Sandbox Code Playgroud)

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"
Run Code Online (Sandbox Code Playgroud)

3.service tomcat restart

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


Nim*_*nji 6

在 android studio 的末尾添加/更改这一行gradle.properties (Global Properties)

...
org.gradle.jvmargs=-XX\:MaxHeapSize\=1024m -Xmx1024m 
Run Code Online (Sandbox Code Playgroud)

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


Tho*_*sen 5

请注意,如果在部署情况下需要此项,请考虑使用Java WebStart(具有"ondisk"版本,而不是网络版本 - 可能在Java 6u10及更高版本中),因为它允许您在十字架中指定JVM的各种参数平台方式.

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


Nee*_*ngh 5

如果您使用的是 Android Studio,只需将这些行添加到gradle.properties文件中

org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8


Mor*_*ndi 5

就我而言,它通过Shared build process heap size在 intellij 设置中分配更多内存来解决。

转到 intellij 设置 > 编译器 > 共享构建过程堆大小

在此输入图像描述