I've run across a piece of code that I am convinced will cause an inadvertent memory leak:
Object user = getUser("Bob");
Map<String, WeakReference<Object>> map = new HashMap<>();
map.put("Bob", new WeakReference( user ) );
The purpose of this map is to cache the Objects and to have them automatically cleared from the map by the GC when they are no longer strongly referenced.
However, the way I see it is if the key isn't a weak reference as well, then once the Object is GC'ed, there will still be an entry in the hash map with the key pointing to null. Hence the map will still contain the same number of rows, just all pointing to null values.
So in the above example, once all strong references to user are released, and the GC destroys the Object, the entry in the map will be equiv to :
map.put("Bob", null );
So unless there is a cleanup routine that flushes all keys with null values, my map will continue to grow.
So then the question becomes how to fix this? Is there a map construct that I can use which will automatically flush my entry if the value is destroyed?
I contemplated doing something like:
Object user = getUser("Bob");
Map<String, WeakReference<Object>> map = new WeakHashMap<>();
map.put(user.getUsername(), new WeakReference( user ) );
But that seems like a very limited use case where my key has to be an object retrieved from my value. With the WeakHashMap my key cannot be a String constant (ie: "Bob") or there won't be any other references to it, and the GC will clear the object from my map.
Is there some other cache construct that provides all this functionality instead?