Is Java HashMap.clear() and remove() memory effective?

103,158

Solution 1

The idea is that clear() is only called when you want to re-use the HashMap. Reusing an object should only be done for the same reason it was used before, so chances are that you'll have roughly the same number of entries. To avoid useless shrinking and resizing of the Map the capacity is held the same when clear() is called.

If all you want to do is discard the data in the Map, then you need not (and in fact should not) call clear() on it, but simply clear all references to the Map itself, in which case it will be garbage collected eventually.

Solution 2

Looking at the source code, it does look like HashMap never shrinks. The resize method is called to double the size whenever required, but doesn't have anything ala ArrayList.trimToSize().

If you're using a HashMap in such a way that it grows and shrinks dramatically often, you may want to just create a new HashMap instead of calling clear().

Solution 3

Another thing to consider is that each element in table is simply a reference. Setting these entries to null will remove the references from the items in your Map, which will then be free for garbage collection. So it isn't as if you are not freeing any memory at all.

However, if you need to free even the memory being used by the Map itself, then you should release it as per Joachim Sauer's suggestion.

Solution 4

You are right, but considering that increasing the array is a much more expensive operation, it's not unreasonable for the HashMap to think "once the user has increased the array, chances are he'll need the array this size again later" and just leave the array instead of decreasing it and risking to have to expensively expand it later again. It's a heuristic I guess - you could advocate the other way around too.

Share:
103,158

Related videos on Youtube

Illarion Kovalchuk
Author by

Illarion Kovalchuk

Core contributor at Gobetween

Updated on May 01, 2020

Comments

  • Illarion Kovalchuk
    Illarion Kovalchuk about 4 years

    Consider the follwing HashMap.clear() code:

     /**
     * Removes all of the mappings from this map.
     * The map will be empty after this call returns.
     */
    public void clear() {
        modCount++;
        Entry[] tab = table;
        for (int i = 0; i < tab.length; i++)
            tab[i] = null;
        size = 0;
    }
    

    It seems, that the internal array (table) of Entry objects is never shrinked. So, when I add 10000 elements to a map, and after that call map.clear(), it will keep 10000 nulls in it's internal array. So, my question is, how does JVM handle this array of nothing, and thus, is HashMap memory effective?

    • Michael Borgwardt
      Michael Borgwardt about 14 years
      10,000 nulls take up all of 40KB (possibly 80 on a 64bit JVM).
    • corsiKa
      corsiKa about 14 years
      @Michael, perhaps, but that's irrelevant: the number can be expanded to any scale. OP is asking on a matter of principle. Maybe the map is huge, maybe the available memory is small. We don't know.
    • james
      james about 14 years
      10000 elements in the map != 10000 entries in the internal table. please learn how the HashMap impl works first...
  • Hank Gay
    Hank Gay about 14 years
    I would also add that this behavior isn't part of the documented contract, so even if you stumbled on implementation that did resize the internal array—which seems unlikely—then you probably shouldn't rely on that unless it explicitly makes it part of the contract.
  • Illarion Kovalchuk
    Illarion Kovalchuk about 14 years
    That's fine, but what if the HashMap is used in some kind of singletone, and always contains some data, so it can't be just replaced by a new instance? In some cases, it can get a big portion of data, which will live there for some time, and after that be removed. But nulls in array will remain. That doesn't look fine.
  • Joachim Sauer
    Joachim Sauer about 14 years
    @Shaman: all you just gave is another reason not to use the singelton pattern ;-)
  • matt b
    matt b about 14 years
    HashMap.Entry is a simple class which holds references to the key, the value, the next Entry, and a hashcode. I'm not sure how much memory a reference takes, but assuming it's 4 bytes, then a HashMap with a million empty slots in it's Entry[] consumes approximately 4MB more memory than a HashMap with no slots would hold. To me, this doesn't sound like much cause for concern; if anything, your singleton should take a more active role in managing it's data (i.e. if it holds a Map which is aggressively getting resized, it should consider creating new instances when going from large to small)
  • corsiKa
    corsiKa about 14 years
    @Shaman, if it was used in a singleton, you could still have a function on the singleton (hopefully synchronized) to create a new instance.
  • bobanahalf
    bobanahalf over 8 years
    To get specific, @JoachimSauer, you mean: