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

sun*_*sun 6 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);
}
Run Code Online (Sandbox Code Playgroud)

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

ass*_*ias 5

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

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


Ste*_*n C 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);
}
Run Code Online (Sandbox Code Playgroud)

原始代码的问题是:

  • 你只创建一个列表,
  • 你不断添加越来越多的元素,和
  • 该代码仅在代码完成时变为垃圾...因为它在整个时间内都在"范围内".

list在循环中移动声明意味着ArrayList在每次循环迭代中创建并填充new ,并在开始下一次迭代时变为垃圾.


有人建议打电话System.gc().它不会在所有帮助你的情况,因为有最少1吨要收集垃圾.总的来说,这是一个坏主意,因为:

  • 保证GC在抛出OOME之前立即运行,
  • JVM可以比运行GC的最佳(即最有效)时间更好地计算出来,
  • System.gc()无论如何,你的电话可能完全被忽略了.可以配置JVM以便System.gc()忽略调用.

1 - 我的学究者想指出,map.put(i, list); map.remove(i);最有可能产生一个Integer很可能变成垃圾的物体.然而,与您无限期增长的ArrayList物体相比,这是"鸡饲料" .