Java 在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

我正在对HashMap、LinkedHashMap插入进行一些性能测试。我正在测试的操作是插入和插入后内存中的大小

我能够进行插入测试,也能够在插入后提取内存中的
大小
,以及使用以下逻辑-

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的大小。