Java数组有最大大小限制吗?

249

Java数组中元素的数量是否有限制?如果有,是多少?


7
您接受了一个错误的答案,请尝试分配这样一个很长的数组(不,我没有内存不足的问题)。 - maaartinus
1
紧密相关:https://dev59.com/rHNA5IYBdhLWcg3wpvpg - Ciro Santilli OurBigBook.com
正确答案是 https://dev59.com/ml0Z5IYBdhLWcg3wfge-。 - Ivan Mamontov
10个回答

206

使用

OpenJDK 64-Bit Server VM (build 15.0.2+7, mixed mode, sharing)

在 MacOS 上,答案似乎是 Integer.MAX_VALUE - 2。一旦你超过了这个值:

cat > Foo.java << "END"
public class Foo {
  public static void main(String[] args) {
    boolean[] array = new boolean[Integer.MAX_VALUE - 1]; // too big
  }
}
END
java -Xmx4g Foo.java

你将获得:

Exception in thread "main" java.lang.OutOfMemoryError:
  Requested array size exceeds VM limit

66
我认为,除非我们愿意对明显错误的答案进行踩,否则踩的想法毫无意义。在现实世界中,五个字节的差别真的很重要吗?当然不是。但是,让我感到担忧的是人们愿意“权威地”给出答案,甚至不去尝试它是否真正可行。至于内存限制,那当然。这就像你问我“你能吃多少颗葡萄?”我回答“这取决于我冰箱里有多少葡萄一样显而易见。” - Kevin Bourrillion
7
你是否知道为什么它不会给你那五个字节?这是否在Java中总是会发生的,还是可能与你计算机的内存或其他东西有关? - Taymon
20
@Kevin Bourrillion:看起来情况已经改变了,在使用Oracle 1.7.0_07版本时,我可以分配最多MAX_VALUE-2个元素。这与我所分配的内容无关,我真的很想知道VM可以用这两个“东西”做什么(长度不适合2个字节)。 - maaartinus
3
@TomášZato,当达到 Integer.MAX_VALUE+1 时,整数会发生溢出。在 Java 中,数组的大小为 int 类型,而不是 long 类型;无论你将什么数据类型存储在数组中,包括字节或引用类型。字符串只是对象引用。 - Has QUIT--Anony-Mousse
8
在JDK 6及以上版本中,数组的最大元素数量为Integer.MAX_VALUE -2=2 147 483 645。如果您使用-Xmx13G运行Java,则可以成功分配这样大小的数组。如果您传递-Xmx12G,它将出现OutOfMemoryError: Java heap space错误。 - Alexey Ivanov
显示剩余13条评论

147

当然,这完全取决于虚拟机。

浏览 OpenJDK 7 和 8 的源代码 java.util.ArrayList, .Hashtable, .AbstractCollection, .PriorityQueue.Vector,你可以看到这个说法被反复提及:

/**
 * Some VMs reserve some header words in an array.
 * Attempts to allocate larger arrays may result in
 * OutOfMemoryError: Requested array size exceeds VM limit
 */
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

这个代码段是由Martin Buchholz (Google) 在2010年5月9日添加的; 由Chris Hegarty (Oracle)进行了审核。

因此,可能可以说最大的“安全”数字应该是2 147 483 639 (Integer.MAX_VALUE - 8),“尝试分配更大的数组可能会导致OutOfMemoryError”。

(是的,Buchholz的独立声明中没有包含支持证据,所以这是一种经过计算的权威申述。即使在OpenJDK本身中,我们也可以看到像return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;这样的代码,这表明MAX_ARRAY_SIZE还没有一个真正的用途。)


为什么我们需要添加“-8”? - JohnWinter
@Pacerier。这个MAX_ARRAY_SIZE只应该在使用ArrayList时才适用,对于像int[] array = new int[some_value_here]这样的数组是不同的,不是吗?为什么一个在ArrayList中定义的常量可以应用于普通数组(用[]定义)?它们在幕后是相同的吗? - Bitcoin Cash - ADA enthusiast
1
@Tiago,不,代码本身与数组的最大大小无关。这只是一个说法。 - Pacerier
@JohnWinter,引用中提到“一些虚拟机在数组中保留了一些标题字”。因此,“-8”是由保留的标题字节所占据的原因。 - Pacerier
1
@Pacerier 2^31(Integer.MAX_VALUE - 8,大约)* 2^2(假设4字节int)= 2 ^ 33。但我认为64位系统至少有48位用于其虚拟地址空间。虚拟地址空间的一部分进入堆段,因此似乎Java中的数组可以比这个大小大得多。我错过了什么吗? - torez233
无论JVM的限制如何,它都必须使用int类型的索引来工作,因此不可能存在大于Integer.MAX_VALUE的索引。 - undefined

40

实际上有两个限制。一个是数组可索引的最大元素,另一个是应用程序可用的内存量。根据可用内存量和其他数据结构使用的内存量,你可能会在达到最大可寻址数组元素之前达到内存限制。


这个答案并不试图回答“可索引数组的最大元素索引值是多少”。 - Simon Forsberg

32
根据这篇文章 http://en.wikipedia.org/wiki/Criticism_of_Java#Large_arrays,Java因不支持超过231−1(约21亿)个元素的数组而受到批评。这是该语言的一个限制;Java语言规范第10.4节规定:

数组必须由int值进行索引...使用long索引值访问数组组件会导致编译时错误。

要支持大型数组还需要更改JVM。这种限制在某些方面表现出来,例如集合被限制为20亿个元素以及无法内存映射大于2 GiB的文件。Java还缺乏真正的多维数组(由单个间接操作访问的连续分配的单个内存块),这限制了科学和技术计算的性能。


8
Java缺少多维数组的语法糖,但你仍然可以通过一点乘法来“拥有”它们(除非数组的总大小超过了前面提到的限制)。 - kbolino
2
@kbolino没错。我相信科学用户足够聪明,能够自己创建多维数组。 - Stefan Reich

15
数组是非负整数索引的,所以您可以访问的最大数组大小将是Integer.MAX_VALUE。另一件事是您可以创建多大的数组。这取决于您的JVM可用的最大内存和数组的内容类型。每个数组元素都有自己的大小,例如,byte = 1字节,int = 4字节,Object引用 = 4字节(在32位系统上)。
所以,如果您的机器上有1MB的可用内存,您可以分配一个byte[1024 * 1024]或Object[256 * 1024]的数组。
回答您的问题 - 您可以分配一个大小为(可用内存/数组项大小)的数组。
总结 - 理论上,数组的最大大小将是Integer.MAX_VALUE。实际上,这取决于您的JVM有多少内存以及其中多少已经分配给其他对象。

4
我尝试创建一个这样的字节数组:

byte[]

byte[] bytes = new byte[Integer.MAX_VALUE-x];
System.out.println(bytes.length);

使用此运行配置:

-Xms4G -Xmx4G

并且 Java 版本:

Openjdk 版本 "1.8.0_141"

OpenJDK 运行时环境(版本 1.8.0_141-b16)

OpenJDK 64 位服务器 VM(版本 25.141-b16,混合模式)

仅适用于 x >= 2,这意味着数组的最大大小为 Integer.MAX_VALUE-2。

超出该值会导致以下错误:

Exception in thread "main" java.lang.OutOfMemoryError: Requested array size exceeds VM limit at Main.main(Main.java:6)


2

数组的最大元素数量为(2^31)−12 147 483 647


6
Java无法分配大小为Integer.MAX_VALUE-1的数组,否则会出现"java.lang.OutOfMemoryError: Requested array size exceeds VM limit"的错误。JDK6及以上版本中允许的最大元素数量为Integer.MAX_VALUE-2= 2,147,483,645。 - Alexey Ivanov

0

是的,Java 数组有限制。Java 使用整数作为数组的索引,JVM 可以存储的最大整数为 2^32,因此您可以在数组中存储 2,147,483,647 个元素。

如果需要超过最大长度,可以使用两个不同的数组,但推荐的方法是将数据存储到文件中。因为文件中存储的数据没有限制。因为文件存储在您的存储驱动器中,而数组存储在 JVM 中。JVM 为程序执行提供了有限的空间。


其他答案表明,即使您有可用的内存,也不可能分配一个 Integer.MAX_VALUE 的数组。 - Alexey Ivanov
2^32 不是 2,147,483,647(即 2^31 - 1)。 - dimm

-1

实际上这是Java的限制,将其限制在2^30-4即1073741820。而不是2^31-1。我不知道为什么,但我在JDK上手动测试过了。2^30-3仍然抛出vm异常

编辑:已修复为-4,在Windows JVM上进行了检查


2
你正在使用32位的JVM。使用64位的JVM,JVM限制将接近2^31。(您还需要可用的堆空间,这不是默认设置,并且会受到物理内存的影响。) - dave_thompson_085

-1
Java数组有限制,因为它是一个整数数组,这意味着它的数组最多可以有2,147,483,647个元素。

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