当 HashMap 或 HashSet 最大容量达到时会发生什么情况?

2022-09-02 13:39:13

就在几分钟前,我回答了一个关于“Java中HashMap的最大可能大小”的问题。正如我一直读到的那样,HashMap是一个可增长的数据结构。它的大小仅受 JVM 内存大小的限制。因此,我认为它的大小没有硬性限制,并相应地回答了这个问题。(这同样适用于 HashSet。

但是有人纠正我说,由于HashMap的size()方法返回int,因此其大小限制。一个完全正确的观点。我只是试图在我的本地测试它,但失败了,我需要超过8GB的内存才能在HashMap中插入超过2,147,483,647个整数,而我没有。

我的问题是:

  • 当我们尝试在 HashMap/HashSet 中插入 2,147,483,647 + 1 个元素时会发生什么?
  • 是否抛出错误?
  • 如果是,哪个错误?如果不是,那么HashMap/HashSet,其已经存在的元素和新元素会发生什么?

如果有人有幸访问具有16GB内存的计算机,则可以实际尝试一下。:)


答案 1

阵列的基础容量必须是 2 的幂(限制为 2^30),当达到此大小时,负载因子将被有效地忽略,阵列停止增长。

此时,碰撞的速率增加。

鉴于hashCode()只有32位,在任何情况下,这都没有意义。

/**
 * Rehashes the contents of this map into a new array with a
 * larger capacity.  This method is called automatically when the
 * number of keys in this map reaches its threshold.
 *
 * If current capacity is MAXIMUM_CAPACITY, this method does not
 * resize the map, but sets threshold to Integer.MAX_VALUE.
 * This has the effect of preventing future calls.
 *
 * @param newCapacity the new capacity, MUST be a power of two;
 *        must be greater than current capacity unless current
 *        capacity is MAXIMUM_CAPACITY (in which case value
 *        is irrelevant).
 */
void resize(int newCapacity) {
    Entry[] oldTable = table;
    int oldCapacity = oldTable.length;
    if (oldCapacity == MAXIMUM_CAPACITY) {
        threshold = Integer.MAX_VALUE;
        return;
    }

    Entry[] newTable = new Entry[newCapacity];
    transfer(newTable);
    table = newTable;
    threshold = (int)(newCapacity * loadFactor);
}

当大小超过 Integer.MAX_VALUE 时,它将溢出。

void addEntry(int hash, K key, V value, int bucketIndex) {
Entry<K,V> e = table[bucketIndex];
    table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
    if (size++ >= threshold)
        resize(2 * table.length);
}

答案 2