HashMap的绝对容量

时间:2011-09-26 11:02:17

标签: java hashmap

我一直在我的代码中使用一个HashMap对象进行一些性能检查,并发现它减慢了在2000-2400个对象内部添加对象的速度。事实上,当它到达大约2400个物体时,它仍然被阻挡,并且不允许更多的条目。这类物品是否存在限制,当它们被记忆存放时,在它们被清空或被回收之前不会允许更多的条目?

非常感谢。

2 个答案:

答案 0 :(得分:5)

我能想到的唯一可以解释问题的是你的对象是否非常大并且你几乎没有堆。当发生这种情况时,JVM可以在很长一段时间内停止尝试清理。在Java 6中,它尝试在它变得非常糟糕之前检测到它并抛出一个OutOfMemoryError(在它完全用完之前但是它无法清理很多)Java 5.0不会这样做。

它可以解释为什么当您丢弃一些物体时,事情会再次加速。


HashMap的标准实现限制在大约7.5亿条目(取决于您如何使用它,例如您的平均负载)它可以拥有的最大容量是2 ^ 30(10亿)并且负载因子为0.75f( ~750m条目)它将尝试增长底层数组,使其不能达到这个大小的两倍。 (因为最大大小为Integer.MAX_VALUE)

您可以使用LinkedHashMap作为缓存,根据您必须提供的规则驱逐“eldset”条目。

但是,除非HashMap已同步,否则它不会阻止。如果失败则会抛出异常。

使Map阻止这种方式的唯一一致方法是出现死锁。

另一种可能发生的方式是,如果您以不安全的方式在两个线程中使用相同的映射。在这种情况下,行为是未定义的,但是我已经看到它导致JVM中的问题(很少),甚至“挂起”所涉及的线程。即使是这种情况,我也希望它在HashMap的增长中具有默认的加载因子,这将是3072(即4096 * 0.75),而不是你看到的值。


即使有一个糟糕的hashCode实现也无法解释这个问题。

static class BadHash {
    @Override
    public int hashCode() {
        return 1;
    }
}

public static void main(String... args) {
    Map<BadHash, Boolean> map = new HashMap<BadHash, Boolean>();
    for (int i = 0; i <= 100000; i++) {
        if (i % 10000 == 0) System.out.println(i + ": " + new Date());
        map.put(new BadHash(), true);
    }
}

在14秒内打印以下内容。

0: Mon Sep 26 12:23:39 BST 2011
10000: Mon Sep 26 12:23:39 BST 2011
20000: Mon Sep 26 12:23:39 BST 2011
30000: Mon Sep 26 12:23:40 BST 2011
40000: Mon Sep 26 12:23:41 BST 2011
50000: Mon Sep 26 12:23:42 BST 2011
60000: Mon Sep 26 12:23:44 BST 2011
70000: Mon Sep 26 12:23:46 BST 2011
80000: Mon Sep 26 12:23:48 BST 2011
90000: Mon Sep 26 12:23:51 BST 2011
100000: Mon Sep 26 12:23:53 BST 2011

答案 1 :(得分:4)

运行此程序(在主类中):

Map<Long, String> map = new HashMap<Long, String>();
for (long l = 0L; l < 100000; l++) {
    map.put(Long.valueOf(l), String.valueOf(l));
}
System.out.println(map.size());

在我的机器上运行,输出和终止的速度很快,我甚至都没有注意到它。

如果HashMap算法良好,

hashCode()可以支持许多元素。显然,你的不好。