我一直在对代码中的一个 HashMap 对象进行一些性能检查,发现它会减慢在大约 2000-2400 个对象内添加对象的速度。事实上,当它达到大约 2400 个对象时,它仍然处于阻塞状态并且不允许更多条目。这种对象是否有一个限制,当它们被保存在内存中时,在它们被清空或回收之前不允许更多的条目?
非常感谢。
最佳答案
我能想到的唯一可以解释这个问题的事情是,如果你的对象非常大并且你几乎用完了堆。发生这种情况时,JVM 可能会停止越来越长的时间来尝试清理。在 Java 6 中,它尝试在情况变得非常糟糕之前检测到这一点并抛出 OutOfMemoryError(在它完全耗尽但未能清理太多之前),Java 5.0 不会这样做。
这可以解释为什么当你丢弃一些物体时事情会再次加速。
<小时/>HashMap 的标准实现限制为大约 7.5 亿个条目(取决于您如何使用它,例如您的平均负载)它可以拥有的最大容量为 2^30(十亿),负载因子为 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
关于java - HashMap绝对容量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7554106/