在HashMap和LinkedHashMap中插入数据后如何计算内存中的大小?

时间:2014-04-16 05:10:50

标签: java hashmap runtime linkedhashmap

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

我能够做到,插入测试并且还能够使用以下逻辑提取size in memory after insertion -

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
...

现在我逐行读取此文件并将其存储在HashMapLinkeddHashMap中,以便我可以在插入后测量内存中的插入性能和大小以及下面的代码。< / p>

我有一个单独的类文件,其中我有两个方法,一个用于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

}

我看到一个非常奇怪的问题 - 对于HashMap性能测试,我可以看到myHashMapMemory中有一些值,但在myLinkedHashMapMemory变量中,它总是具有零值或负值。

有没有想过为什么会这样,以及如何避免这个问题?一般来说,为什么我看到零值或负值?

4 个答案:

答案 0 :(得分:1)

要测量已用内存,我们需要关闭线程分配缓冲区-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个字节

答案 1 :(得分:0)

快速提问:为什么有两种相同的方法......?只需将地图作为参数传递?

但是除此之外:如果你按顺序运行它们,那么当你进入第二种方法时,gc可能已经从第一个哈希映射中踢出并删除了东西。任何基于这种原始方法的内存扫描都可能无法给出正确的估计值。

换句话说:如果第二张地图已被gc-ed,则第二张地图可能占据与第一张地图相同的存储空间。此外,根据jvm和设置,如果未使用(例如,在其中的所有内容都已被gc-ed之后),jvm实际上可以将操作系统的内存返回给操作系统。

答案 2 :(得分:0)

这可能是因为其他人提到的gc的行为。 我想说的是,对于如此大量的数据,地图实现都很糟糕。我已经测试过,每当数据大于几百万字节时,你必须自己为这种工作实现Map接口。

答案 3 :(得分:0)

我认为Evgeniy是对的。在jdk1.7中,TLAB设置为true default。当新线程启动时,即使没有创建对象也将分配TLAB。因此,您可以关闭TLAB并再次尝试。 由于gc因素,你应该尝试更多次,并且你最好提高伊甸园区域以避免年轻的gc。