【问题标题】:Java crashing before filling up heap spaceJava 在填满堆空间之前崩溃
【发布时间】:2012-02-15 02:00:22
【问题描述】:

我有这个需要处理大量数据的 java 模拟器。它工作得很好,但是我得到了int[100000][100][2] 的数组以及其他大数组。该程序说它的内存不足。 (Java.lang.outOfMemoryError)

一切都很好,我只是给它更多的内存,但它似乎总是用完大约 300M,即使我允许它 2GB。这一切都来自观看任务管理器。

我的系统有问题吗,或者这只是我需要处理的 java 问题?

@DanielPryden

操作系统:板载 Win 7 32Bit 4GB 内存

JVM 命令:java -Xmx2048M -Xms2048M 模拟器

错误数据:必须从 IDE 获取(使用 IntelliJ)。我不知道如何从 cmd 执行此操作。我想这就是你要找的东西。

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at Simulator.main(Simulator.java:63)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)

【问题讨论】:

  • 在运行 java 时是否使用 -Xmx2GB 标志来指定更大的堆大小?
  • 你'允许'怎么办?用-Xmx?那应该可以。
  • 我使用 -Xmx2048M -Xms2048M 从 cmd 运行
  • @PetroSemeniuk:泛型不适用于基元,但基元数组不是基元。 List<int[100][2]> 是完全合法的。也就是说,ArrayList 不会比数组更好,因为它分配了一个连续的数组作为其后备存储。
  • @Daniel:是的,关于泛型中的基元数组,您是对的——这是可能的。但是,我认为 ArrayList 会起作用,因为它将是引用数组([][] 数组仍然可以存在于不同的内存块中)。不需要连续的内存块(虽然我可能是错的)

标签: java out-of-memory


【解决方案1】:

您可能会遇到堆碎片问题。即使你设置了 -Xmx2GB,上面的整数数组也需要一块连续内存。我建议也固定最小堆大小,例如 -Xms2GB。由于操作系统开销、其他进程等原因,这当然要求您的机器实际上有远高于 2GB 的容量。

或者,您可以重新访问您的数据结构,看看您是否真的需要这样一个连续的块。以某种方式分解它可能会减少对大块连续内存的需求。

【讨论】:

    【解决方案2】:

    如果您在 32 位 Windows 操作系统上运行,则不可能分配完整的 2GB。即使您对 Windows 内部结构不屑一顾,您将获得的最大可用地址空间是 3GB,即便如此,它也不会全部是连续的(并且 JVM 需要连续空间来构建 Java 堆)。在实践中,使用 Sun/Oracle JVM,我从来没有能够成功分配一个大于 1.5GB 的堆——如果你使用 JNI,最大可能的堆会被你链接的任何 DLL 减少在。

    如果您真的需要一个大堆,我首先建议您尽可能迁移到 64 位操作系统。其次,正如这里的其他答案所指出的那样,如果您可以分配非连续内存,那将更有可能成功。使用LinkedList 或其他在单独的块中分配数据的结构。这里有一些权衡;您可能希望每个块都包含一个至少 64Kb 的数组。

    最后,如果您能找到一种方法将处理拆分为单独的进程,您可能会获得更好的结果——也就是说,运行多个 Java 实例,每个实例都有自己的一组数据进行操作,并使用套接字或文件在他们之间进行交流。也就是说,使用 32 位 Windows 操作系统,您可能仍然无法使用 4GB 内存,更不用说更大的内存了。

    【讨论】:

    • 所有的答案听起来都是很好的建议,但我认为这个更简洁。不过,向你们所有人致敬。
    【解决方案3】:

    堆内存分为三个空间:

    • 老一代
    • 幸存者空间
    • 伊甸空间

    默认情况下,虚拟机会在每个集合处增大或缩小堆,以尝试将每个集合处的可用空间与活动对象的比例保持在特定范围内。此目标范围由参数 -XX:MinHeapFreeRatio= 和 -XX:MaxHeapFreeRatio= 设置为百分比,总大小以 -Xms 为界,以 -Xmx 为界。

    我的 jvm(1.6.26) 中的默认比率是 30/70,因此老年代对象的最大大小(使用 -Xmx1G)被限制为 700Mb。

    但是,您可以使用 jvm 选项调整生成大小。例如,您可以使用参数 -Xmx1G -XX:NewRatio=10 运行您的类,并且可以在内存中放置更大的对象。

    看起来 Java 的设计初衷不是为了在内存中保存大型单体对象(如数组)。应用程序中内存的典型使用是一堆相对较小的对象的图形,通常只有在所有空间都用完空间时才会出现 OutOfMemoryError。

    以下是几篇有用(且读起来很有趣)的文章:

    Ergonomics in the 5.0 Java[tm] Virtual Machine

    Tuning Garbage Collection with the 5.0 Java[tm] Virtual Machine

    编辑:我无法在我的机器上重现它(Mac OS X,8Gb RAM)。考虑到单个数组占用大约 200Mb+ 的内存,我同意 brettw 的观点,即没有这种大小的连续内存块会导致这个问题(不是生成大小)。至于修复 - 将集合与普通数组一起使用或购买更多内存(推荐:-))

    【讨论】:

    • 您能举个例子吗?我尝试了不同的方法来使用您所描述的内容,但似乎没有帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-08-19
    • 2015-05-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-08
    • 2021-03-08
    相关资源
    最近更新 更多