2014-09-01 54 views
2

我需要使用HashMap的键是Long数据类型和值是一些用户对象,其定义为:使用为什么删除大量(〜80%)的密钥后,HashMap的大小没有变化?

dummy.add(SomeLong,new SomeClass(SomeParameters); 
加入

HashMap <Long,SomeClass> dummy=new HashMap<>(); 

最初,这dummy HashMap中包含了约1000万<key,value>对,

消耗的内存是7-8GB。创建此映射后,80-90%的条目将被删除:

for (Iterator<Entry<Long, SomeClass>> it = collisionMap.entrySet().iterator(); it.hasNext();) { 
    Map.Entry<Long,SomeClass> entry = it.next();   
    if(SomeCondition) { 
     it.remove(); 
    } 
} 

删除这些条目后使用的内存仍然相同。我检查了Runtime.getRuntime().totalMemory()Runtime.getRuntime().freeMemory()

现在的问题是为什么内存在这个remove()操作后未被回收? 我在程序过程中创建了大约1000-2000次这种类型的hashmap。而它给java.lang.OutOfMemoryError: GC overhead limit exceeded错误:(

谁能帮助? 感谢

*****************更新/附加信息**** ************

SomeClass被定义为:

Class SomeClass { 
    private ArrayList <Integer> list1; 
    private ArrayList <Integer> list2;  
    public SomeClass(int l,List <Integer> l2) { 
    list2=l2; 
    list1=new ArrayList<>(); 
    list1.add(l); 
    }  
    public void addList1(int l) { list1.add(l); } 
    public ArrayList <Integer> getList1() { return list1; } 
    public ArrayList <Integer> getList2() { return list2; }  
} 

由于种种原因,我早些时候曾计划使用BitSet数据类型而不是ArrayList list1。如果我替换list1' by a BitSet variable and set thebit instead of adding l to list1'然后用这个类的对象创建虚拟HashMap,那么关于内存的结果是不同的。令人惊讶的是,内存在HashMap上的remove操作之后被回收。例如。在移除HahsMap内存中约80%的条目后,也将约减少40%。

分配给ArrayList的内存没有被回收吗? :(:(

+2

当你删除条目本身被删除,但散列表仍然分配给它的“峰值”大小,但这应该是几乎不可估量的 - 大部分空间在obj中这些条目占用了实际散列表空间的几倍。你几乎可以肯定地看到你以某种方式将它们“连在一起”或“一些”之类的“泄漏”的物体。 – 2014-09-01 03:39:13

+0

您需要学习如何使用堆分析器并找出程序的哪部分保留对值对象的引用。 – 2014-09-01 04:32:22

+0

可能是[错误java.lang.OutOfMemoryError:超出GC开销限制]的欺骗(http://stackoverflow.com/questions/1393486/error-java-lang-outofmemoryerror-gc-overhead-limit-exceeded) – markspace 2014-09-01 05:16:15

回答

0

java.lang.OutOfMemoryError: GC overhead limit exceeded

这表明你不必使用过多的内存(虽然地图可能消耗高达80MB为您的情况的内部节点阵列),但在GC没有足够呼吸的空间(最大堆限制)或CPU时间(GC时间限制)可以做的工作给你的分配方案。

你最有可能来调整您的GC参数,以避免此问题。