Java 在HashMap和LinkedHashMap中插入数据后,如何计算内存中的大小?
我正在对HashMap、LinkedHashMap插入进行一些性能测试。我正在测试的操作是插入和插入后内存中的大小 我能够进行插入测试,也能够在插入后提取内存中的Java 在HashMap和LinkedHashMap中插入数据后,如何计算内存中的大小?,java,hashmap,runtime,linkedhashmap,Java,Hashmap,Runtime,Linkedhashmap,我正在对HashMap、LinkedHashMap插入进行一些性能测试。我正在测试的操作是插入和插入后内存中的大小 我能够进行插入测试,也能够在插入后提取内存中的大小,以及使用以下逻辑- long myTotalMemoryBefore = Runtime.getRuntime().totalMemory(); /* Fill the hashmap or linkedhashmap */ long myTotalMemoryAfter = Runtime.getRuntime().tota
大小
,以及使用以下逻辑-
long myTotalMemoryBefore = Runtime.getRuntime().totalMemory();
/* Fill the hashmap or linkedhashmap */
long myTotalMemoryAfter = Runtime.getRuntime().totalMemory();
long myHashMapMemory = myTotalMemoryAfter - myTotalMemoryBefore;
我有一个文本文件,其中包含200万个英语单词,其频率为这种格式-
hello 100
world 5000
good 2000
bad 9000
...
现在,我正在逐行读取此文件,并将其存储在HashMap
和LinkeddHashMap
中,这样我就能够测量插入后的插入性能和内存大小,以及下面的代码
我有一个类文件,其中有两个方法,一个用于HashMap
,另一个用于LinkedHashMap
性能测试,它们都是按顺序运行的,首先运行HashMap测试,然后运行LinkedHashMap测试-
public void hashMapTest() {
Map<String, String> wordTest = new HashMap<String, String>();
long myTotalMemoryBefore = Runtime.getRuntime().totalMemory();
String line = reader.readLine();
while (line != null && !line.isEmpty()) {
// split the string on whitespace
String[] splittedString = line.split("\\s+");
String split1 = splittedString[0].toLowerCase().trim();
Integer split2 = Integer.parseInt(splittedString[1].trim());
// now put it in HashMap as key value pair
wordTest.put(split1, split2);
line = reader.readLine();
}
long myTotalMemoryAfter = Runtime.getRuntime().totalMemory();
long myHashMapMemory = (myTotalMemoryAfter - myTotalMemoryBefore) / 1024;
System.out.println(myHashMapMemory);
}
public void linkedHashMapTest() {
Map<String, String> wordTest = new LinkedHashMap<String, String>();
long myTotalMemoryBefore = Runtime.getRuntime().totalMemory();
String line = reader.readLine();
while (line != null && !line.isEmpty()) {
// split the string on whitespace
String[] splittedString = line.split("\\s+");
String split1 = splittedString[0].toLowerCase().trim();
Integer split2 = Integer.parseInt(splittedString[1].trim());
// now put it in LinkedHashMap as key value pair
wordTest.put(split1, split2);
line = reader.readLine();
}
long myTotalMemoryAfter = Runtime.getRuntime().totalMemory();
long myLinkedHashMapMemory = (myTotalMemoryAfter - myTotalMemoryBefore) / 1024;
System.out.println(myLinkedHashMapMemory); // this is coming as zero always or negative value
}
public void hashMapTest(){
Map wordTest=new HashMap();
long myTotalMemoryBefore=Runtime.getRuntime().totalMemory();
字符串行=reader.readLine();
while(line!=null&&!line.isEmpty()){
//在空白处拆分字符串
String[]splittedString=line.split(\\s+);
String split1=splittedString[0].toLowerCase().trim();
整数split2=Integer.parseInt(splittedString[1].trim());
//现在将其作为键值对放在HashMap中
wordTest.put(split1,split2);
line=reader.readLine();
}
long myTotalMemoryAfter=Runtime.getRuntime().totalMemory();
长myHashMapMemory=(myTotalMemoryAfter-myTotalMemoryBefore)/1024;
System.out.println(myHashMapMemory);
}
public void linkedHashMapTest(){
Map wordTest=新建LinkedHashMap();
long myTotalMemoryBefore=Runtime.getRuntime().totalMemory();
字符串行=reader.readLine();
while(line!=null&&!line.isEmpty()){
//在空白处拆分字符串
String[]splittedString=line.split(\\s+);
String split1=splittedString[0].toLowerCase().trim();
整数split2=Integer.parseInt(splittedString[1].trim());
//现在将其作为键值对放入LinkedHashMap
wordTest.put(split1,split2);
line=reader.readLine();
}
long myTotalMemoryAfter=Runtime.getRuntime().totalMemory();
long myLinkedHashMapMemory=(myTotalMemoryAfter-myTotalMemoryBefore)/1024;
System.out.println(myLinkedHashMapMemory);//始终为零或负值
}
我看到了一个非常奇怪的问题-对于HashMap性能测试,我可以看到myHashMapMemory
中有一些值,但在myLinkedHashMapMemory
变量中,它总是有零值或负值
有没有想过为什么会发生这种情况,以及如何避免这个问题?一般来说,为什么我会看到零值或负值?快速问题:为什么有两个相同的方法。。。?只需将映射作为参数传递 但除此之外:如果您按顺序运行它们,那么当您使用第二个方法时,gc可能已经启动并删除了第一个哈希映射中的内容。基于这种粗糙方法的任何内存扫描都可能无法给出正确的估计
换句话说:如果第二个映射已被gc-ed,则它可能占用与第一个映射相同的内存空间。此外,根据jvm和设置,jvm实际上可以在未使用的情况下(例如,在对其中的所有内容进行gc-ed后)将内存返回给操作系统.要测量已用内存,我们需要关闭线程分配缓冲区
-XX:-UseTLAB
,然后
Runtime rt = Runtime.getRuntime();
long m0 = rt.totalMemory() - rt.freeMemory(); //used memory
Object obj = new Object();
long m1 = rt.totalMemory() - rt.freeMemory();
System.out.println(m1 - m0);
将在内存中显示java.lang.Object的正确大小-在我的例子中为16字节这可能是因为gc的行为,正如其他人提到的那样。
我想说的是,对于如此大的数据量,两种地图实现都是不好的。我已经测试过,当数据大于几百万字节时,您必须自己实现映射接口来完成这类工作 我认为Evgeniy是对的。在jdk1.7中,TLAB设置为true默认值。当新线程启动时,即使尚未创建对象,也会分配TLAB。因此,您可以关闭TLAB并重试。
由于gc因素,您应该尝试更多次,最好提高Eden区域的空间以避免年轻的gc。我们可以从命令行传递此参数吗<代码>-XX:-UseTLAB因为我将从命令提示符运行我的runnable jar?而且,我应该使用freeMemory而不是totalMemory?1)是的,java-XX。。。。;2) freeMemory在我的简单例子中是可以的,但是最好使用usedMemory=runtime.totalMemory()-runtime.freeMemory())谢谢:我如何增加Eden区域的大小以避免年轻的GC。有什么想法吗?您可以使用-Xmn参数,例如:-Xmx2048M-Xms2048M-Xmn1024M。young:old的默认比率为1:2,因此您只能提高-Xmx和-Xms,并且只要-Xmn小于-Xmx/-Xms,您还可以通过-Xmn参数分配young的大小。