2012-12-05 52 views
6

Java代码如下:Hashmap.remove()被调用后立即发生垃圾回收吗?

Random r = new Random(1234697890); 
HashMap<Integer, List<Integer>> map = new HashMap<Integer, List<Integer>>(); 
List<Integer> list = new ArrayList<Integer>(); 

for(int i=0;i<100000;i++){ 
    for(int j=0;j<1000;j++){ 
     list.add(r.nextInt(100000)); 
    } 
    map.put(i, list); 
    map.remove(i); 
} 

i达到37553,java.lang.OutOfMemoryError: Java heap space发生。
似乎垃圾收集不会发生在循环中。
现在我想知道如何解决这个问题。

+0

你总是添加到列表中,并永远不会从中删除。 –

+2

仅供参考,番石榴有一个'Multimap'套类来实现'Map >'并且负责为你创建列表。 –

+0

@JohnB - 这个问题怎么可能相关? – Perception

回答

5

尝试重写代码如下,你不应该OOME的...

Random r = new Random(1234697890); 
HashMap<Integer, List<Integer>> map = new HashMap<Integer, List<Integer>>(); 

for(int i=0;i<100000;i++){ 
    List<Integer> list = new ArrayList<Integer>(); 
    for(int j=0;j<1000;j++){ 
     list.add(r.nextInt(100000)); 
    } 
    map.put(i, list); 
    map.remove(i); 
} 

与原代码的问题是:

  • 你只创建一个列表,
  • 您继续添加更多元素,并且
  • 该列表只在代码完成时变成垃圾...因为它在整个时间范围内。

移动循环内的list声明意味着一个新的ArrayList创建并填充在每个循环迭代,并成为垃圾,当你开始下一次迭代。


有人建议打电话System.gc()。这对你的情况根本无济于事,因为垃圾收集的时间很短。而在一般情况这是一个坏主意,因为:

  • 的GC保证了OOME抛出之前已经立即运行,
  • 的JVM可以找出比你是何时能最好的(即最有效的更好)运行GC的时间,
  • 无论如何,您对System.gc()的调用可能完全被忽略。 JVM可以配置为忽略对System.gc()的调用。

1 - 我心中的学究想指出的是,map.put(i, list); map.remove(i);是最有可能产生Integer对象,最有可能成为垃圾。然而,与您无限期增长的对象相比,这是“鸡饲料”。

5

您一直使用相同的List,当循环退出时,它包含100000 * 1000个项目。要使GC摆脱列表,您需要将其范围缩小到for(i)循环内。

换句话说,映射和列表在任何时候都可以访问该代码段,因此不符合收集条件。

+0

或者,您可以增加堆大小,以便该方法能够完成,并且所有内容都可以GC'd,然后:D – Esailija

0

在你的情况下,你继续填充相同的list(即使你从该HashMap中删除它,它仍然作为局部变量存在)。

JVM承诺在投掷OutOfMemoryError之前做一个完整的垃圾收集。所以你可以肯定没有什么可以清理的。

0

您的代码

List<Integer> list = new ArrayList<Integer>(); 

for(int i=0;i<100000;i++){ 
    for(int j=0;j<1000;j++){ 
     list.add(r.nextInt(100000)); 
    } 
    map.put(i, list); 
    map.remove(i); 
} 

相同

List<Integer> list = new ArrayList<Integer>(); 

for(int i=0;i<100000 * 1000; i++) { 
    list.add(r.nextInt(100000)); 
} 

正如你可以看到它的列表,而不是它保留了所有的整数的映射。顺便尝试一下,看看会发生什么;)

list.add(r.nextInt(128));