Java数组的最大限制

6

我正在尝试使用Java创建2D数组,代码如下:

int[][] adjecancy = new int[96295][96295];

但是它出现了以下错误:
JVMDUMP039I Processing dump event "systhrow", detail "java/lang/OutOfMemoryError" at 2017/04/07 11:58:55 - please wait.
JVMDUMP032I JVM requested System dump using 'C:\eclipse\workspaces\TryJavaProj\core.20170407.115855.7840.0001.dmp' in response to an event
JVMDUMP010I System dump written to C:\eclipse\workspaces\TryJavaProj\core.20170407.115855.7840.0001.dmp
JVMDUMP032I JVM requested Heap dump using 'C:\eclipse\workspaces\TryJavaProj\heapdump.20170407.115855.7840.0002.phd' in response to an event
JVMDUMP010I Heap dump written to C:\eclipse\workspaces\TryJavaProj\heapdump.20170407.115855.7840.0002.phd

解决这个问题的一种方法是增加JVM内存,但我正在尝试提交代码参加在线编码挑战。在那里,它也失败了,我将无法更改设置。

是否有任何标准限制或指导,用于创建不应超过的大数组?


2
它必须是一个二维数组吗? - stholzm
3
您正在尝试分配37GB的内存。这相当多,即使增加JVM内存也需要一台大型计算机。您需要找到一个更智能的算法(这就是为什么它被称为编码挑战)。 - Henry
1
你在问是否可能分配40GB的内存而不使用40GB的内存?不可能。如果你告诉我们你为什么要这样做,也许我们可以帮助改进你的解决方案。 - shmosel
你应该考虑一种不需要在主内存中存储将近100亿个整数的解决方案。 - Joni
2
变量的名称表明您正在创建一个邻接矩阵。您试图以天真的方式完成它,这只适用于小矩阵。如果您能以最显而易见的方式解决它,那么这不会是什么挑战。 - Kayaman
5个回答

14
int[][] adjecancy = new int[96295][96295];

当您这样做时,您试图分配 96525*96525*32 位,几乎为 37091 MB,即将近37GB。这在仅针对Java的PC上获得内存是极其不可能的。

我认为您在程序初始化时不需要那么多数据。可能您需要查看ArrayList,它可以动态分配大小,并在运行时保持释放的关键点要考虑。

创建数组没有限制或限制。只要您有内存,就可以使用它。但请记住,不应持有使JVM生命周期繁忙的内存块。


3

数组显然必须适合内存。如果不适合,典型的解决方案有:

  • 你真的需要 int(最大值为2,147,483,647)吗?也许 byte(最大值为127)或short就足够了?byteint小8倍。
  • 数组中是否有非常多相同的值(如零)?尝试使用稀疏数组。

例如:

Map<Integer, Map<Integer, Integer>> map = new HashMap<>();
map.put(27, new HashMap<Integer, Integer>()); // row 27 exists
map.get(27).put(54, 1); // row 27, column 54 has value 1.

它们需要更多的内存来存储值,但基本上没有数组空间限制(您可以使用Long而不是Integer作为索引使它们变得非常大)。

  • 也许您不知道数组应该有多长?尝试使用ArrayList,它可以自动调整大小。对于二维数组,请使用ArrayListsArrayList

  • 如果其他方法都无法帮助,请使用RandomAccessFile将过大的数据存储到文件系统中。在好的工作站上,100 GB左右的数据不是问题,您只需要计算所需的偏移量即可。文件系统显然比RAM慢得多,但是配备良好的SSD驱动器可能还能承受。


1
我非常喜欢这个答案,因为它不仅明显表述了问题,还提出了多种可能的解决方案,而不破坏挑战的难度。这个挑战可能有诀窍,比如使用更节省内存的稀疏矩阵表示方法。 - stholzm

1
建议分配的最大堆大小为机器RAM大小的1/4。在Java中,1个int占用4个字节,您的数组分配需要约37.09GB的内存。
在这种情况下,即使我假设您将整个堆分配给一个数组,您的机器也应该有大约148GB的RAM。那是巨大的。
请参阅以下内容。
参考文献: http://docs.oracle.com/javase/8/docs/technotes/guides/vm/gc-ergonomics.html 希望这可以帮助您。

0

这取决于你的JVM可用的最大内存和数组的内容类型。对于int,我们有4个字节的内存。现在,如果您的计算机上有1 MB的内存,则可以容纳最多1024 * 256个整数(1 MB = 1024 * 1024字节)。记住这一点,您可以相应地创建您的二维数组。


0

你可以创建的数组取决于JVM堆大小。

96295 * 96295 * 4(每个数字的字节数)= 37,090,908,100字节=约34.54 GBytes。大多数竞争性代码评测机中的JVM内存不足以支持这么大的内存。因此会出现错误。

要了解在给定堆大小下可以使用的数组大小,请使用不同的-Xmx设置运行此代码片段:

    Scanner scanner = new Scanner(System.in);
    while(true){
        System.out.println("Enter 2-D array of size: ");
        size = scanner.nextInt();

        int [][]numbers = new int[size][size];
        numbers = null;
    }

例如,使用 -Xmx 512M 的话,可以得到一个包含大约10k+个元素的二维数组。

通常,大多数在线评测系统在评判提交代码时使用的堆大小为~1.5-2GB


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