调用Hashmap.remove()后立即发生垃圾收集吗?

时间:2012-12-05 13:09:36

标签: java garbage-collection out-of-memory

Java代码如下:

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发生 垃圾收集似乎不会在循环中发生 现在我想知道如何解决这个问题。

4 个答案:

答案 0 :(得分:5)

您始终使用相同的List,循环退出时包含100000 * 1000个项目。要使GC能够删除列表,您需要将其范围缩小到for(i)循环内。

换句话说,地图和列表都可以在该段代码中随时访问,因此不符合收集条件。

答案 1 :(得分: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()。在你的情况下它根本没有帮助,因为要收集最少的 1 垃圾。总的来说,这是一个坏主意,因为:

  • GC保证在抛出OOME之前立即运行,
  • 当运行GC的时间最好(即最有效)时,JVM可以比你更好地解决问题,
  • 无论如何,您对System.gc()的通话可能完全被忽略。可以配置JVM以忽略对System.gc()的调用。

1 - 我的学究者想指出map.put(i, list); map.remove(i);最有可能生成一个很可能变成垃圾的Integer对象。但是,与您无限增长的ArrayList对象相比,这是“鸡饲料”。

答案 2 :(得分:0)

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

JVM承诺在抛出OutOfMemoryError之前进行完整的垃圾收集。所以你可以肯定没有什么可以清理的。

答案 3 :(得分: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,而不是保留所有整数的地图。顺便试试这个,看看会发生什么;)

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