ChatGPT解决这个技术问题 Extra ChatGPT

如何处理“java.lang.OutOfMemoryError: Java heap space”错误?

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

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

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

我可以重写我的一些代码以频繁地将对象持久保存到文件系统(使用数据库是同一件事)以释放内存。它可以工作,但它可能也有很多工作。

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

64 MB 的默认最大堆大小来自 J2SE 5.0 之前的版本。有关 J2SE 8.0 的信息,请参阅 docs.oracle.com/javase/8/docs/technotes/guides/vm/… 处的“垃圾收集器人体工程学”。
如果您来到这里是因为每个 OOM 问题都与这个问题有关,请确保您还检查了:stackoverflow.com/questions/299659/… 它提供了在 OOM 之前“及时”清理内存引用的解决方案。 SoftReferences 可能是解决您实际问题的工具。
Sun/Oracle JVM 在指定要使用的内存量方面一直非常严格(如果单独使用,还有一些有趣的默认值)。这是当时 Microsoft JVM 的优点之一 - 它速度很快,并且可以使用机器拥有的任何内存。
就我而言,我错过了要添加到项目中的 gradle.properties 文件

H
Hearen

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

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

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

如果您确定分配这些对象是有原因的,并且您需要保留引用(取决于您在做什么,这可能是这种情况),您只需要在启动程序时增加最大堆大小。但是,一旦您进行了内存分析并了解了您的对象是如何分配的,您应该对您需要多少内存有一个更好的了解。

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


OpenJDK 和 OracleJDK 捆绑了分析器 - jvisualvm。如果您想要更多便利,我建议您使用商业 Yourkit。
使用关闭未使用的对象和数组,比如 resultsSet.close();文件输出流.close();文件输出流.flush(); ,我使用 resultsSet.close() 并且神奇地工作。
H
Hearen

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

See here for details


如何永远设置这个参数?因为我正在使用“gradlew assemble”命令。
运行->运行配置->单击参数->内部VM参数类型-Xms1g -Xmx2g
H
Hearen

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

以下是 Eclipse Helios/Juno/Kepler:

鼠标右键点击

 Run As - Run Configuration - Arguments - Vm Arguments, 

然后添加这个

-Xmx2048m

嗨 bighostkim 和 cuongHuyTo,“参数”在哪里......我可以看到运行配置。请给我打电话。我需要从 gmail 下载和存储近 2000 个联系人。由于内存不足异常而崩溃
@AndroiRaji:您将鼠标右键单击到具有可运行 main 的 Java 类(即“public static void main(String[] args)”),然后选择 Run As - Run Configuration。然后“参数”是 Main 之后的选项卡(您会看到选项卡 Main、Arguments、JRE、Classpath、Source、Environment、Common)。
intellih 会怎样?
P
PeakGen

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

尽可能使用局部变量。确保您选择了正确的对象(例如:在 String、StringBuffer 和 StringBuilder 之间进行选择)为您的程序使用良好的代码系统(例如:使用静态变量 VS 非静态变量)其他可以在您的代码上工作的东西。尝试使用多线程移动


这是真的。我正在尝试解决一个问题,即我在 AWT 线程上遇到 OOM,但如果我使用不同的新线程,我不会遇到 OOM 问题。我在网上只能找到增加 AWT 线程的堆大小。
@Ash:是的,解决核心问题而不是寻找石膏。
Java 中的垃圾收集和内存管理方法应该解决其前辈的所有这些 malloc-dealloc 复杂性:(当然我完全同意这个答案,可惜默认设置并不能轻松编写带有精简数据的代码- 尽快清理的结构。
我不同意。您最初需要将其设置为某个值。如果结果证明是不够的,并不一定意味着您的应用程序不好。也许你太乐观了。在这种情况下,将其设置为更高的值是一种有效的解决方案。
H
Hearen

大警告 ---- 在我的办公室,我们发现(在某些 Windows 机器上)我们不能为 Java 堆分配超过 512m 的空间。事实证明,这是由于其中一些机器上安装了卡巴斯基反病毒产品。卸载该 AV 产品后,我们发现我们可以分配至少 1.6gb,即 -Xmx1600m(m 是强制性的,否则会导致另一个错误“Too small initial heap”)有效。

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


H
Hearen

我想添加来自 oracle trouble shooting 文章的建议。

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

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

可能的原因:

简单的配置问题,指定的堆大小对于应用程序来说是不够的。应用程序无意中持有对对象的引用,这可以防止对象被垃圾收集。过度使用终结器。

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

垃圾回收后,对象排队等待最终确定,这将在稍后发生。终结器由服务终结队列的守护线程执行。如果终结器线程无法跟上终结队列,那么 Java 堆可能会填满,并且会抛出这种类型的 OutOfMemoryError 异常。

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


H
Hearen

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

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

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

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


H
Hearen

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


JVMJ9VM007E 无法识别命令行选项:-Xmx 无法创建 Java 虚拟机。否决票
H
Hearen

请按照以下步骤操作:

从 tomcat/bin 打开 catalina.sh。将 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" 重启你的tomcat


H
Hearen

默认情况下,开发 JVM 使用小尺寸和小配置来实现其他与性能相关的功能。但是对于生产,您可以调整例如(另外它可以存在应用程序服务器特定的配置)->(如果仍然没有足够的内存来满足请求并且堆已经达到最大大小,则会发生 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 内部数据结构中。


H
Hearen

我在其他地方读到了你可以尝试的地方 - 捕获 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();

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

在 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


知道为什么我们需要将它们保持在 1:1 或 1:1.5 的比例吗?
M
Muhammad Raqib

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

那我想你应该这样做

cd android/ && ./gradlew clean && cd ..

H
Hearen

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

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

只需安装 jdk1.6 并转到 eclipse 的首选项并设置您安装的 jav1 1.6 的 jre 路径。检查你的 VM 参数,让它成为任何东西。只需在 VM 参数中存在的所有参数的下方添加一行 -Xms512m -Xmx512m -XX:MaxPermSize=...m(192m)。

我认为它会工作...


H
Hearen

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

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

最终,您最好的选择是在性能保持可接受的情况下尽可能限制您的记忆保留。正如之前的评论所指出的,内存总是有限的,但你的应用程序应该有一个处理内存耗尽的策略。


N
Nima Ganji

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

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

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


H
Hearen

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

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


Java WebStart 正在逐步淘汰。我还不知道合适的替代品。
T
Talha Akbar

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

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

它应该工作。您可以相应地更改 MaxPermSize 以解决您的堆问题


C
CodingEra

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

org.gradle.jvmargs=-Xmx4096m -XX:MaxPermSize=4096m -XX:+HeapDumpOnOutOfMemoryError
org.gradle.daemon=true
org.gradle.parallel=true
org.gradle.configureondemand=true

H
Hearen

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

转到'运行',然后-->'设置项目配置'-->'自定义'-->弹出窗口的'运行'-->'VM选项'-->填写'-Xms2048m -Xmx2048m' .


M
Morteza Bandi

在我的情况下,它通过在 intellij 设置中为 Shared build process heap size 分配更多内存来解决。

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

https://i.stack.imgur.com/UV6Ii.png


a
aristotll

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

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

如需更多信息,请查看Wildfly Heap Issue


H
Hearen

如果您继续分配和保留对对象的引用,您将填满您拥有的任何内存量。

一种选择是在切换选项卡时关闭和打开透明文件(您只保留指向文件的指针,当用户切换选项卡时,您关闭并清理所有对象......这会使文件更改速度变慢...但是...),并且可能只在内存中保留 3 或 4 个文件。

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

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

我在内存泄漏方面看到的一些提示是:

--> 请记住,如果您将某些东西放入集合中,然后忘记了它,您仍然对它有一个强引用,因此请取消集合、清理它或用它做一些事情......如果不是,您会发现内存泄漏很难找到。

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

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


i
itzo

安卓工作室

File -> Invalidate Caches and Restart 为我解决了它:)


s
samuelru

如果在执行 junit 测试后立即发生此错误,则应执行 Build -> Rebuild Project。


C
Chukwunazaekpere

如果在 react-native 中生成 APK 期间出现此错误,请 cd 进入项目中的 android 文件夹并执行以下操作:

./gradlew clean

然后

./gradlew assembleRelease

如果错误仍然存在,请重新启动您的机器。


N
Neeraj Singh

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

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


n
nccc

如果一切都失败了,除了增加最大堆大小之外,还要尝试增加交换大小。对于 Linux,截至目前,相关说明可在 https://linuxize.com/post/create-a-linux-swap-file/ 中找到。

如果您要在嵌入式平台上编译一些大的东西,这会有所帮助。


A
Antonin Dioulo

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

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

我操作的新修改:

-Xmx512m -XX:MaxPermSize=512m

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

谢谢


H
Haranath Boggarapu

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

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

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

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