Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does garbage collection happen immediately after Hashmap.remove() is called?

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.

like image 713
sun Avatar asked Dec 05 '12 13:12

sun


2 Answers

Try rewriting the code as follows and you should not get OOME's ...

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);
}

The problem with your original code is that:

  • you only create one list,
  • you keep adding more and more elements to it, and
  • that list only becomes garbage when the code completes ... because it is "in scope" the whole time.

Moving the list declaration inside the loop means that a new ArrayList 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:

  • the GC is guaranteed to have run immediately before an OOME is thrown,
  • the JVM can figure out better than you can when is the best (i.e. most efficient) time to run the GC,
  • your call to System.gc() may be totally ignored anyway. The JVM can be configured so that calls to System.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 an Integer object that most likely becomes garbage. However, this is "chicken feed" compared to your indefinitely growing ArrayList object.

like image 84
Stephen C Avatar answered Sep 21 '22 23:09

Stephen C


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.

like image 36
assylias Avatar answered Sep 20 '22 23:09

assylias