地图是一种“可扩展”结构——当它达到其容量时,它会调整大小。因此,您的地图使用的 40% 的空间可能实际上是空的。如果您知道地图中有多少条目,则可以使用临时构造函数以最佳方式调整地图大小:
Map<xx,yy> map = new HashMap<> (length, 1);
即使您这样做,地图仍将使用比所包含项目的实际大小更多的空间。
更详细地说:HashMap 的大小在达到(容量 * loadFactor)时翻倍。HashMap 的默认加载因子是 0.75。
例子:
- 想象一下您的地图的容量(大小)为 10,000 个条目
- 然后,您在地图中放置了 7,501 个条目。容量 * loadFactor = 10,000 * 0.75 = 7,500
- 因此,您的 hashmap 已达到其调整大小阈值并调整为 (容量 * 2) = 20,000,尽管您只持有 7,501 个条目。这会浪费很多空间。
编辑
这个简单的代码让您了解实际发生的情况 - 输出是:
threshold of empty map = 8192
size of empty map = 35792
threshold of filled map = 8192
size of filled map = 1181712
threshold with one more entry = 16384
size with one more entry = 66640
这表明如果您添加的最后一项恰好强制地图调整大小,它可以人为地增加地图的大小。诚然,这并不能说明您观察到的整体效果。
public static void main(String[] args) throws java.lang.Exception {
Field f = HashMap.class.getDeclaredField("threshold");
f.setAccessible(true);
long mem = Runtime.getRuntime().freeMemory();
Map<String, String> map = new HashMap<>(2 << 12, 1); // 8,192
System.out.println("threshold of empty map = " + f.get(map));
System.out.println("size of empty map = " + (mem - Runtime.getRuntime().freeMemory()));
mem = Runtime.getRuntime().freeMemory();
for (int i = 0; i < 8192; i++) {
map.put(String.valueOf(i), String.valueOf(i));
}
System.out.println("threshold of filled map = " + f.get(map));
System.out.println("size of filled map = " + (mem - Runtime.getRuntime().freeMemory()));
mem = Runtime.getRuntime().freeMemory();
map.put("a", "a");
System.out.println("threshold with one more entry = " + f.get(map));
System.out.println("size with one more entry = " + (mem - Runtime.getRuntime().freeMemory()));
}