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

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

我可以增加 最大堆大小 使用 命令行 java 的选项,但这需要弄清楚可用的 RAM 并编写一些启动程序或脚本。此外,增加一些 有限 最大没有 最终 摆脱这个问题。

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

如果您可以向我指出上述想法的细节或一些替代方案,例如 自动虚拟内存,动态扩展堆大小, , 那挺棒的。

有帮助吗?

解决方案

最终,无论您在什么平台上运行,您始终可以使用有限的最大堆。在 Windows 32 位中,大约是这样 2GB (不是特定的堆,而是每个进程的内存总量)。碰巧的是,Java 选择将默认值变小(大概是这样,程序员就无法创建内存分配失控的程序,而不会遇到此问题,并且必须准确检查它们在做什么)。

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

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

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

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

其他提示

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

详情请参阅此处.

你可以指定 预测您的项目需要多少堆空间

以下是针对 日食太阳神/朱诺/开普勒:

鼠标右键单击

 Run As - Run Configuration - Arguments - Vm Arguments, 

然后添加这个

-Xmx2048m

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

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

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

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

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

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

或者你可以这样做 Run --> Run Configurations --> select the "JRE" tab --> 然后输入-Xmx1024m

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

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

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

线程 thread_name 中出现异常: java.lang.OutOfMemory错误:Java堆空间

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

可能的原因:

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

  2. 应用程序无意中保存了对对象的引用, ,这可以防止对象被垃圾收集。

  3. 过度使用终结器.

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

垃圾收集, ,对象排队等待 定稿, ,这发生在稍后的时间。 终结器 由为终结队列提供服务的守护线程执行。如果 终结器 线程无法跟上终结队列,那么 Java 堆可能会被填满,这种类型的 内存不足错误 将抛出异常。

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

请按照以下步骤操作:

  1. 打开 catalina.sh 来自 tomcat/bin。

  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

简单的方法解决 OutOfMemoryError 在java中是通过使用JVM选项来增加最大堆大小 -Xmx512M, ,这将立即解决您的 OutOfMemoryError。当我在构建项目时在 Eclipse、Maven 或 ANT 中遇到 OutOfMemoryError 时,这是我的首选解决方案,因为根据项目的大小,您很容易耗尽内存。

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

export JVM_ARGS="-Xms1024m -Xmx1024m"

参考链接

默认情况下,开发 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内部数据结构。

我也遇到过与java堆大小相同的问题。

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

  1. 只需安装jdk1.6并进入eclipse的首选项并按照您安装的方式设置jav1 1.6的jre路径即可。

  2. 检查你的VM参数并让它成为任何东西。只需在VM参数中的所有参数中添加一行,即-XMS512M -XMX512M -XX:MaxPermsize = ... M(192m)。

我认为它会起作用...

我在其他地方读到您可以尝试 - catch 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();

如果您需要在运行时监控内存使用情况, java.lang.management 套餐优惠 MBeans 可用于监视虚拟机中的内存池(例如,伊甸园空间、终身代等)以及垃圾收集行为。

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

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

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

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

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

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

欲了解更多信息,请查看 Wildfly 堆问题

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

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

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

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

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

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

我看到的有关内存泄漏的一些提示是:

--> 请记住,如果您将某些内容放入集合中,然后忘记了它,那么您仍然对它有很强的引用,因此使集合无效,清理它或用它做一些事情......如果没有的话你会发现内存泄漏很难发现。

--> 也许,使用带有弱引用的集合(weakhashmap...)可以帮助解决内存问题,但是你 必须 小心一点,因为你可能会发现你要找的东西已经被收集了。

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top