The Java code is as follows:
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);
}
when i
reaches 37553 , java.lang.OutOfMemoryError: Java heap space
happens.
It seems that garbage collection does not happen in the loop.
Now I wonder how to fix the problem.
Try rewriting the code as follows and you should not get OOME's ...
The problem with your original code is that:
Moving the
list
declaration inside the loop means that a newArrayList
is created and filled in each loop iteration, and becomes garbage when you start the next iteration.Someone suggested calling
System.gc()
. It won't help at all in your case because there is minimal1 garbage to be collected. And in general it is a bad idea because:System.gc()
may be totally ignored anyway. The JVM can be configured so that calls toSystem.gc()
are ignored.1 - The pedant in me would like to point out that
map.put(i, list); map.remove(i);
is most likely generating anInteger
object that most likely becomes garbage. However, this is "chicken feed" compared to your indefinitely growingArrayList
object.Your code
is the same as
As you can see its the List, not the map which is retaining all the integers. BTW Try this instead and see what happens ;)
You use the same List all the time, which contains 100000 * 1000 items when the loop exits. To enable GC to get rid of your list, you need to reduce its scope to within the
for(i)
loop.In other words, both map and list are reachable at all time in that piece of code and are therefore not eligible for collection.
In your case you keep filling the same
list
(even though you remove it from that HashMap, it still exists as a local variable).The JVM promises to do a full garbage collect before throwing an
OutOfMemoryError
. So you can be sure there is nothing left to clean up.