HashSet,Vector,LinkedList的最大大小

时间:2011-10-03 07:25:48

标签: java collections

HashSetVectorLinkedList的最大尺寸是多少?我知道ArrayList可以存储超过3277000个数字。

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

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

5 个答案:

答案 0 :(得分:53)

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

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

  • HashSet在内部使用HashMap,因此它具有相同的最大尺寸
    • A HashMap使用的数组总是具有2的幂,因此它最多可以是2 30 = 1073741824个元素(因为下一个2的幂)大于Integer.MAX_VALUE)。
    • 通常元素的数量最多是桶的数量乘以负载因子(默认为0.75)。 然而,当HashMap停止调整大小时,它仍然允许您添加元素,利用每个存储桶通过链接列表进行管理的事实。因此,HashMap / HashSet中元素的唯一限制是内存。
  • Vector内部使用一个数组,其最大大小为Integer.MAX_VALUE,因此它不能支持多个元素
  • LinkedList 使用数组作为底层存储,因此不会限制大小。它使用经典的双向链表结构,没有固有限制,因此其大小仅由 以可用内存为界。请注意,如果LinkedList大于Integer.MAX_VALUEint会错误地报告大小,因为它使用size()字段来存储大小,int的返回类型为{ {1}}也是。

请注意,虽然Collection API 确实定义了Collection个元素超过Integer.MAX_VALUE的行为。最重要的是它说明了the size() documentation

  

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

请注意,虽然HashMapHashSetLinkedList 似乎支持的不仅仅是Integer.MAX_VALUE个元素,但 none 其中以这种方式实现size()方法(即它们只是让内部size字段溢出。)

这让我相信其他操作在这种情况下没有明确定义。

所以我说使用最多 Integer.MAX_VLAUE元素的通用集合是安全。如果您知道您需要存储更多内容,那么您应该切换到实际支持此功能的专用集合实现。

答案 1 :(得分:8)

在所有情况下,您可能会受到JVM堆大小的限制,而不是其他任何东西。最终你总是会遇到数组,所以我非常怀疑他们中的任何一个都会管理超过2个 31 - 1个元素,但是你很可能会在那之前耗尽堆反正。

答案 2 :(得分:3)

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

答案 3 :(得分:3)

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

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

增加负载系数会增加集合的最大大小。例如载荷因子为10允许100亿个元素。 (值得注意的是,HashSet相对于1亿个元素的效率相对较低,因为32位哈希码的分布开始看起来不那么随机,并且冲突的数量增加了)

Vector的容量增加一倍,从10开始。这意味着它将无法增长到大约13.4亿。将初始大小设置为2 ^ n-1会让您的头部空间略微增加。

BTW:如果可以,请使用ArrayList而不是Vector。

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

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

答案 4 :(得分:2)

如其他答案中所述,阵列无法达到2 ^ 31个条目。其他数据类型受此限制,或者最终可能误报其大小()。但是,在某些系统上无法达到这些理论极限:

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

普通数组可以达到它的理论极限,但只有一个字节数组,一个长度为2 ^ 31-1的短数组将消耗大约2 ^ 32 + 38字节。

一些Java VM引入了一个使用压缩指针的新内存模型。通过调整指针对齐,可以用32字节指针引用稍多于2 ^ 32个字节。大约四倍多。这足以导致LinkedList size()变为负数,但不足以允许它回绕到零。

64位系统有64位指针,使所有指针的数量增加了一倍,使非数组列表更加丰富。这也意味着支持的最大容量会精确地跳到2 ^ 64个字节。这足以使2D阵列达到其理论最大值。 byte [0x7fffffff] [0x7fffffff]使用的内存大约等于40 + 40 *(2 ^ 31-1)+(2 ^ 31-1)(2 ^ 31-1)= 40 + 40 ( 2 ^ 31-1)+(2 ^ 62-2 ^ 32 + 1)