Guava MapMaker().weakKeys().makeMap() vs WeakHashMap
Asked Answered
D

1

6

We have a Scala server that is getting a node tree using Protocol Buffers over a socket and we need to attach additional data to each node.

In a single threaded context and when both the node tree and the associated data will have their strong references removed at the same time (due to going out of scope), is there any reason to use Google Guava's MapMaker with weakKeys() over using WeakHashMap? It seems that with MapMaker, one pays for synchronized access, which isn't needed in this case.

As an aside, it would be useful if MapMaker were to give access to the equivalence settings so one could choose reference equality but not care about weak or soft references.

Darrondarrow answered 17/11, 2010 at 5:3 Comment(0)
D
6

One significant downside to WeakHashMap is that it is not an "identity map". That is, it uses equals() and hashCode (rather than == and identityHashCode) on keys, which really doesn't make sense for weak keys. You can work around this bug by making sure that your keys use identity equality in their equals method.

Done answered 20/11, 2010 at 7:41 Comment(7)
Thanks Laurence, I quickly scanned the Javadoc and assumed it would be implemented using == and identityHashCode, but doing a closer reading matches your description.Darrondarrow
Also, one could still use java.util.HashMap and write a custom ReferenceEquivalence<T> that contains a single T and uses == and identityHashCode?Darrondarrow
You could, but you'll need something to purge dead keys from the HashMap. As an aside, I haven't verified this by looking at the code, but I wonder if the removal of dead keys/values is part of the reason MapMaker uses a ConcurrentMap.Done
@LaurenceGonsalves Why using equals() and hashCode() doesn't make sense for weak keys?Lanza
@Lanza Typically you want the value for any key you put to survive so long as the key is otherwise reachable. Say o1.equals(o2), but o1 != o2. If you put a value for o1 and also for o2 in the map (even if you merge the values somehow) only one of these keys will be there afterwards. Lets say o1 is the one that remains. Now we can look up either o1 or o2 and get our value. Fine, until later if o1 becomes unreachable, but o2 is still reachable. Because the map had a weak ref to o1, the mapping may get deleted, and if we look up o2, we won't find anything.Done
@LaurenceGonsalves Think about it: let map be a HashMap (strong, no weak), map.put(o1); map.put(o2); map.remove(o1); Then what should we get from map.get(o2)? It is equivalent to weakMap: weakMap.put(o1); weakMap.put(o2);, and later, the GC collects the o1 (same effect: weakMap.remove(o1))Lanza
@Lanza the point is that things you don't want removed can get removed. If you only use put and get (not iteration or deletion) on a map with weak keys, it should behave exactly like a regular map, except that values that are no longer reachable (via get) get cleaned up. A weak map with non-identity keys violates that expectation, as the value for a key can get automatically removed before the key has become unreachable.Done

© 2022 - 2024 — McMap. All rights reserved.