我需要知道Java中的地图何时放大。为此,我需要一个公式来计算良好的初始容量。
在我的项目中,我需要一个包含大对象的大地图。因此,我想通过指定适当的初始容量来防止调整地图大小。通过反思,我研究了地图的行为。
package com.company;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
Map m = new HashMap();
int lastCapacity = 0, currentCapacity = 0;
for (int i = 1; i <= 100_000; i++) {
m.put(i,i);
currentCapacity = getHashMapCapacity(m);
if (currentCapacity>lastCapacity){
System.out.println(lastCapacity+" --> "+currentCapacity+" at "+i+" entries.");
lastCapacity=currentCapacity;
}
}
}
public static int getHashMapCapacity(Map m){
int size=0;
Field tableField = null;
try {
tableField = HashMap.class.getDeclaredField("table");
tableField.setAccessible(true);
Object[] table = (Object[]) tableField.get(m);
size = table == null ? 0 : table.length;
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return size;
}
}
输出为:
0-> 16 at 1项。
16-> 32,共13个条目。
32-> 64,共有25个条目。
64-> 128,共有49个条目。
128-> 256在97个条目上。
256-> 512个,共193个条目。
512-> 1024,共385个条目。
1024-> 2048(在769个条目上)。
2048-> 4096在1537个条目上。
4096-> 8192在3073个条目上。
8192-> 16384(在6145个条目上)。
16384-> 32768,共有12289个条目。
32768-> 65536,共24577个条目。
65536-> 131072,共有49153个条目。
131072-> 262144,输入98305。
我可以假设地图总是这样吗? Java 7和Java 8之间有什么区别吗?
答案 0 :(得分:0)
检查这种行为的最简单方法是查看openjdk源。这些都是免费提供的,而且相对容易阅读。
在这种情况下,检查HashMap,您将看到一些详细的实施说明,这些内容说明了大小调整的工作原理,将什么负载因子用作阈值(这正在驱动您所看到的行为),甚至如何决定是否将树木用于垃圾箱。通读该内容,如果不清楚,请返回。
通过扩展非常便宜的操作,代码已进行了很好的优化。我建议在进行任何调整之前,使用配置文件获取一些性能问题与扩展有关的证据。
答案 1 :(得分:0)
根据文档:
设置初始容量时,应考虑映射中的预期条目数及其负载因子,以最大程度地减少重新哈希操作的次数。 如果初始容量大于最大条目数除以负载因子,则将不会进行任何哈希操作。 https://docs.oracle.com/javase/8/docs/api/java/util/HashMap.html