我在试图找出一个特定情况下的最佳容量和负载系数。我想我大概明白了,但我还是很感激比我更有见识的人的确认。:)
如果我知道我的 HashMap 将包含,比如说,100个对象,并且将花费大部分时间拥有100个对象,我猜测最佳值是初始容量100和负载因子1?或者我需要容量101,还是有其他陷阱?
编辑: 好的,我留出几个小时做了一些测试。以下是结果:
编辑2: 我也添加了一些图表。在初始化 HashMap 并将其填满到最大容量的情况下,下面是负载因子0.75和1之间的区别。在 y 刻度上,时间以 ms 表示(越小越好) ,x 刻度表示大小(对象的数量)。因为大小是线性变化的,所需的时间也是线性增长的。
看看我有什么。下面两个图表显示了负载因子的差异。第一个图表显示了当 HashMap 被填充到容量时会发生什么; 由于调整大小,负载因子0.75的性能更差。然而,情况并不总是更糟,而且有各种各样的颠簸和跳跃——我想 GC 在这方面有很大的作用。负载系数1.25的性能与1相同,因此不包括在图表中。
这个图表证明了0.75由于调整大小而变得更糟; 如果我们将 HashMap 填充到一半的容量,0.75并没有变得更糟,只是... ... 不同(它应该使用更少的内存,并且具有不明显的更好的迭代性能)。
我还想展示一样东西。这样就可以获得所有三个负载因子和不同 HashMap 大小的性能。除了负荷因子1有一个尖峰外,其余都是一致的,变化不大。我真的很想知道那是什么(可能是 GC,但谁知道呢)。
下面是感兴趣的人的代码:
import java.util.HashMap;
import java.util.Map;
public class HashMapTest {
// capacity - numbers high as 10000000 require -mx1536m -ms1536m JVM parameters
public static final int CAPACITY = 10000000;
public static final int ITERATIONS = 10000;
// set to false to print put performance, or to true to print get performance
boolean doIterations = false;
private Map<Integer, String> cache;
public void fillCache(int capacity) {
long t = System.currentTimeMillis();
for (int i = 0; i <= capacity; i++)
cache.put(i, "Value number " + i);
if (!doIterations) {
System.out.print(System.currentTimeMillis() - t);
System.out.print("\t");
}
}
public void iterate(int capacity) {
long t = System.currentTimeMillis();
for (int i = 0; i <= ITERATIONS; i++) {
long x = Math.round(Math.random() * capacity);
String result = cache.get((int) x);
}
if (doIterations) {
System.out.print(System.currentTimeMillis() - t);
System.out.print("\t");
}
}
public void test(float loadFactor, int divider) {
for (int i = 10000; i <= CAPACITY; i+= 10000) {
cache = new HashMap<Integer, String>(i, loadFactor);
fillCache(i / divider);
if (doIterations)
iterate(i / divider);
}
System.out.println();
}
public static void main(String[] args) {
HashMapTest test = new HashMapTest();
// fill to capacity
test.test(0.75f, 1);
test.test(1, 1);
test.test(1.25f, 1);
// fill to half capacity
test.test(0.75f, 2);
test.test(1, 2);
test.test(1.25f, 2);
}
}