Using .clear() or letting the GC take care of it

2019-07-23 19:38发布

问题:

In a portion of my code, two LinkedHashMaps are created, like so:

Map<Byte, Integer> hash1 = new LinkedHashMap<Byte, Integer>();
Map<Byte, Integer> hash2 = new LinkedHashMap<Byte, Integer>();

After that, a for-loop is ran to add values into their respective HashMap, and then the HashMaps are ran through another loop used for packet creation. Would it be better to call .clear() after the second loop is called, or just let the garbage collector take care of it?

回答1:

If you don't call clear(), the GC won't take care of it, because the objects will still be referenced by the hashmap until it goes out of scope.

If the hashmap is going out of scope anyway, you can let the GC handle it. It likely won't make a measurable difference to clear it first.



回答2:

Calling clear() on these maps is likely to be an expensive waste of time, from the perspective of garbage collection.

There are three cases to consider:

  • If the variables containing the (only) HashMap references are about to go out of scope, calling clear() on them is a waste of time. Even assigning null to the variables is a (miniscule) waste of time.

    The HashMap objects will be collected next time the GC is run on the heap that contains them. Calling clear() won't make this happen faster, and won't reduce the work done by the GC.

  • If the variables are not about to go out of scope, but you are not going to reuse the HashMaps, then assigning null to them may make the HashMaps eligible for GC a bit sooner, but the JVM may deal with this case anyway. Calling clear() is a waste of time, as above.

  • If the variables are not going out of scope, and you are going to reuse the HashMaps, then clearing them may be the right thing to do. However the real purpose of calling clear() would be to get rid of old (and presumably unwanted) map entries that are liable to slow down hash table operations, and that could result in incorrect results.

(This is an elaboration of the comments on @squacknull's answer.)


To understand why calling clear doesn't help the GC, you need to understand how the HotSpot collectors work. The HotSpot collectors are "copying" collectors that copy from a "from" space to a "to" space. The work is done by recursively tracing the reachable objects in the "from" space and copying them to the "to" space. Then, any remaining objects are checked to see if they need to be finalized, and the finalizable objects are recursively traced and copied to "to" space. Finally, the "from" space is zeroed, and the GC is done. (It is more complicated than that, when you consider generations, concurrent collectors and so on, but lets not go there ...)

Assuming that the HashMap is unreachable and not finalizable, then neither phases of marking it will find either it, its internal objects (i.e. the hash array or the chains) or the keys and values in the map ... assuming the latter are not reachable by some other route. Thus, clearing the hash array (which is what clear() does) is just clearing elements of an object that wasn't going to be traced anyway. It has no effect on what the GC has to do.