HashSet,Vector,LinkedList的最大大小

什么是HashSetVectorLinkedList的最大大小? 我知道ArrayList可以存储超过3277000个数字。

但是列表的大小取决于内存(堆)的大小。 如果达到最大值,则JDK将引发OutOfMemoryError

但是我不知道HashSetVectorLinkedList中元素数量的限制。

这些结构没有规定的最大尺寸。

实际的实际大小限制可能在Integer.MAX_VALUE (即2147483647,大约20亿个元素)的区域中,因为这是Java中数组的最大大小。

  • HashSet在内部使用HashMap ,因此它具有与此相同的最大尺寸
    • 一个HashMap使用一个总是2的幂的数组,因此它最多可以是2 30 = 1073741824个元素大(因为2的下一个幂比Integer.MAX_VALUE )。
    • 正常情况下 ,元素的数量至多是桶的数量乘以负载因子(默认为0.75)。 但是 ,当HashMap停止resize时,它仍然允许您添加元素,利用每个存储桶通过链接列表进行pipe理的事实。 因此, HashMap / HashSet元素的唯一限制就是内存。
  • 一个Vector在内部使用一个最大尺寸正好是Integer.MAX_VALUE的数组,所以它不能支持比这个多的元素
  • LinkedList 使用数组作为底层存储,所以不会限制大小。 它使用了一个没有固有限制的经典的双向链表结构,所以它的大小受可用内存的限制。 请注意,如果LinkedList大于Integer.MAX_VALUE ,它将错误地报告大小,因为它使用int字段来存储大小, size()的返回types也是int

请注意,虽然Collection API 确实定义了具有多个Integer.MAX_VALUE元素的Collection应该如何工作。 最重要的是它声明了size()文档 :

如果此集合包含多个Integer.MAX_VALUE元素,则返回Integer.MAX_VALUE

请注意,虽然HashMapHashSetLinkedList 似乎支持多于Integer.MAX_VALUE元素,但是没有一个以这种方式实现size()方法(即它们只是让内部size字段溢出)。

这导致我相信在这种情况下其他的操作也不是很好的定义。

所以我会说使用这些通用集合最多可以使用 Integer.MAX_VLAUE元素。 如果你知道你需要存储更多,那么你应该切换到专门的集合实现,实际上支持这个。

在所有情况下,您可能会受JVM堆大小的限制,而不是其他任何东西。 最终你总是会对arrays感兴趣,所以我非常怀疑他们中的任何一个都会pipe理超过2 31 – 1个元素,但是在这之前你很可能会用完堆。

最大大小取决于JVM的内存设置,当然还有可用的系统内存。 每个列表条目的内存消耗的特定大小在各个平台之间也不同,所以最简单的方法可能是运行简单的testing。

这很大程度上取决于实施细节。

HashSet使用一个数组作为底层存储,默认情况下它会在集合满75%时尝试增长。 这意味着如果您尝试添加超过750,000,000个条目,它将会失败。 (它不能将数组从2 ^ 30增长到2 ^ 31个条目)

增加载荷系数会增加集合的最大尺寸。 例如10的载入因子允许100亿个元素。 (值得注意的是,由于32位哈希码的分布开始看起来不那么随机,并且碰撞的数量增加,所以HashSet在1亿个元素中效率相对较低)

Vector的容量翻倍,从10开始。这意味着它将无法增长到约13.4亿。 将初始大小重新设置为2 ^ n-1会给您稍微多一些的空间。

顺便说一句:使用ArrayList而不是Vector,如果可以的话。

LinkedList没有无限制的限制,可以增长超过21亿。 此时,size()可以返回Integer.MAX_VALUE,但是某些函数(如toArray)将会失败,因为它不能将所有对象放入数组中,而是使用第一个Integer.MAX_VALUE而不是抛出exception。

正如@Joachim Sauer指出的那样,当前的OpenJDK可能会返回大于Integer.MAX_VALUE的错误结果。 例如它可能是一个负数。

正如其他答案所述,数组不能达到2 ^ 31条目。 其他数据types受到这个限制,或者它们可能会错误地报告它们的大小()。 然而,这些理论上的限制在一些系统上是不能达到的:

在一个32位的系统上,可用的字节数永远不会超过2 ^ 32。 假设你没有操作系统占用内存。 一个32位的指针是4个字节。 任何不依赖数组的东西都必须至less包含一个指针,这意味着对于不使用数组的东西,最大条目数是2 ^ 32/4或2 ^ 30。

一个普通的数组可以达到理论上的限制,但是只有一个字节数组,一个长度为2 ^ 31-1的短数组会占用大约2 ^ 32 + 38个字节。

一些Java虚拟机引入了一个使用压缩指针的新内存模型。 通过调整指针alignment,可以用32个字节的指针来引用稍多于2 ^ 32个字节。 四倍左右。 这足以导致LinkedList大小()变成负数,但不足以允许它绕回到零。

一个64位的系统有64位指针,使所有的指针两倍大,使非数组列表更加丰富。 这也意味着支持的最大容量正好跳转到2 ^ 64字节。 这足以使2Darrays达到其理论最大值。 字节[0x7fffffff] [0x7fffffff]使用大致等于40 + 40 *(2 ^ 31-1)+(2 ^ 31-1) (2 ^ 31-1)= 40 + 40 (2 ^ 31-1)+ (2 ^ 62-2 ^ 32 + 1)