COLLECTION MEMORY SIZES IN JDK 7U40
Because underused collections are quite problematic in many applications, JDK 7u40 introduced
a new optimization into the ArrayList and HashMap implementations: by default (e.g., when no
size parameter is used in the constructor), these classes no longer allocate any backing store for
the data. The backing store is only allocated when the first item is added to the collection.
This is an example of the lazy-initialization technique discussed in Chapter 7 , and in testing of
several common applications, it resulted in an improvement in performance due to reduced need
for GC. These applications had a lot of such collections that were never used; lazily allocating the
backing store for those collections was a performance win. Because the size of the backing store
already had to be checked on every access, there was no performance penalty for checking to see
if the backing store had already been allocated (though the time required to create the initial back-
ing store did move from when the object was created to when data was first inserted into the ob-
Similarly, a HashMap is the fastest way to look up items based on some key value, but if there
is only one key, then the HashMap is overkill compared to using a simple object reference.
Even if there are a few keys, maintaining a few object references will consume much less
memory than a full HashMap object, with the resulting (positive) effect on GC.
Along those lines, one important difference to know regarding the memory use of collection
classes is the difference in size between a HashMap object and a ConcurrentHashMap object.
Prior to Java 7, the size of an empty or sparsely populated ConcurrentHashMap object was
quite large: over 1 KB (even when a small size was passed to the constructor). In Java 7, that
size is only 208 bytes (compared to 128 bytes for an empty HashMap constructed without a
specified size, and 72 bytes for a HashMap constructed with a size of 1).
This size difference can still be important in applications where there is a proliferation of
small maps, but the optimizations made in Java 7 make that difference much less significant.
There are existing performance recommendations (including some by me) that urge avoiding
the ConcurrentHashMap class in applications where memory is important and the number of
maps is large. Those recommendations center around the trade-off of possible faster access to
the map (if it is contended) against the increased pressure on the garbage collector that the
larger maps cause. That trade-off still applies, but the balance is now much more in favor of
using the ConcurrentHashMap .