堆空间内存不足

50

我的应用程序目前消耗了相当多的内存,因为正在运行物理模拟。问题在于,通常在第51次模拟时,Java会抛出错误,而这往往是由于堆空间不足(我的程序最终要运行数千个模拟)。

是否有任何方法可以不仅增加堆空间,还可以修改程序,使堆空间在每次运行后被清除,以便我可以运行任意数量的模拟?

编辑:谢谢大家。原来模拟器软件没有在每次运行后清除信息,而我已经将这些运行结果都存储在了一个ArrayList中。


8
听起来像是内存泄漏。 - Jason S
2
如果随着你运行越来越多的模拟,你的内存占用不断增加,那么你就有了内存泄漏。你需要找出为什么在模拟结束时你的内存没有被回收。 - mjr
是的,可能是内存泄漏问题,我不记得它的名字了,但它是一个IBM应用程序,可以让你直观地看到每个线程和堆栈。这个工具帮助我们在几年前发现了Hibernate的内存泄漏问题。我会尝试更新您的名称。 - Cygnusx1
@randomafk:这些模拟之间是否有依赖关系?你的程序是否正确地支持多线程?如果答案都是“否”,那么解决问题的一个非常简单的方法就是从shell脚本中执行模拟。这样,即使你的Java应用程序是单线程的,你也可以在x个核心上运行模拟并仅收集结果。除此之外,显而易见的解决方案是不要“清空”堆空间,而是*a)停止内存泄漏和b)*使用更少占用内存的方法(例如使用比默认Java库更好的库,如Trove)。 - SyntaxT3rr0r
你是遇到了标准的OOME还是PermGen类型的?你可以使用JVisualVM来监控虚拟机(如果启用了JMX端口),这样你就可以确定发生了什么。 - djangofan
9个回答

38

无法在程序运行时动态增加堆大小,因为Java虚拟机在启动时分配了堆空间。

但是,您可以使用此命令

java -Xmx1024M YourClass

将内存设置为1024,

或者,您可以设置最小和最大值。

java -Xms256m -Xmx1024m YourClassNameHere

1
这不是“min”,而是“starting”内存选项(因此在“ms”标志中有“s”)。 - McSonk

20
如果你正在使用大量的内存并且面临内存泄漏问题,那么你可能需要检查一下是否使用了大量具有许多元素的ArrayList或HashMap。
ArrayList是作为动态数组实现的。Sun/Oracle的源代码显示,当向一个已满的ArrayList中插入一个新元素时,会创建一个原始数组大小的1.5倍的新数组,并将元素复制过去。这意味着你可能会浪费每个使用的ArrayList中高达50%的空间,除非你调用它的trimToSize方法。或者更好的方法是,如果你事先知道要插入的元素数量,则调用构造函数并将初始容量作为参数。
我没有仔细研究HashMap的源代码,但乍一看似乎每个HashMap中的数组长度必须是2的幂,使其成为另一种动态数组实现。请注意,HashSet本质上是HashMap的包装器。

13

有各种工具可用于帮助诊断此问题。JDK包括JVisualVM,它可以让您附加到正在运行的进程并显示可能正在失控的对象。Netbeans周围有一个包装器,效果相当不错。Eclipse有Eclipse Memory Analyzer,这是我最常用的一个,似乎更好地处理大型转储文件。还有一个命令行选项 -XX:+HeapDumpOnOutOfMemoryError ,它会在程序崩溃时给您一个文件,基本上是您进程内存的快照。您可以使用上述任何工具来查看它,在诊断此类问题时,它确实可以帮助很多。

根据程序工作的难度,它可能只是JVM不知道何时进行垃圾收集的简单情况,您也可以查看并行垃圾收集选项。


1
不应该是 -XX:+HeapDumpOnOutOfMemoryError(+而不是-)吗? http://www.oracle.com/technetwork/java/javase/clopts-139448.html#gbzrr - Eli Acherkan
可能是,我复制文本的原始页面来自同一家公司的另一个不同但类似的页面。感谢您的纠正。 - mezmo
JVisualVM的链接也已更改为:https://docs.oracle.com/javase/6/docs/technotes/guides/visualvm/intro.html - Mohsen Abasi

6
我也遇到了同样的问题。我通过以下步骤进行构建解决了这个问题。
-->右键单击项目,选择RunAs->Run configurations
将您的项目选择为BaseDirectory。在目标位置上输入eclipse:eclipse install。
-->在第二个选项卡中,将-Xmx1024m作为VM参数输入。

4
我想补充说明,这个问题与常见的Java内存泄漏类似。
当JVM垃圾收集器无法随着时间推移清除Java / Java EE应用程序的"废弃"内存时,OutOfMemoryError: Java heap space 将是结果。
首先进行适当的诊断非常重要:
  • 启用详细:垃圾回收。这将允许您了解随时间推移内存增长的模式。
  • 生成和分析JVM堆转储。这将使您了解应用程序的内存占用情况,并确定内存泄漏的来源。
  • 您还可以使用Java分析器和运行时内存泄漏分析器,例如Plumbr,来帮助您完成此任务。

2

尝试添加-Xmx以获取更多内存(java -Xmx1024M YourClass),并且不要忘记停止引用您不再需要的变量(内存泄漏)。


1

你是否保留了不再需要的变量引用(例如来自先前模拟的数据)?如果是这样,那么你就有了内存泄漏。你只需要找到发生泄漏的地方,并确保在不再需要这些变量时删除对它们的引用(如果它们超出作用域,则会自动发生此操作)。

如果你实际上需要所有来自先前模拟的数据保留在内存中,你需要增加堆大小或更改算法。


0
Java应该在所有对象不再被引用时为您清除堆空间。但它通常不会将其释放回操作系统,而是保留该内存供自己内部重用。也许检查一下是否有一些未被清除的数组或其他东西。

0
不行。堆由垃圾回收器在其自己的时间内清除。您可以使用 System.gc() 要求运行,但不能保证运行。
首先尝试通过设置 -Xmx256m 来增加内存。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接