WeakHashMap and strongly referenced value

2019-03-20 04:09发布

问题:

Javadocs says "When a key has been discarded its entry is effectively removed from the map".

But unless there is another thread that occasionally removes such Map.Entry entries, won't the value objects be strongly referenced by the map? But since there is no such thread running, only the get method invocations can remove such entries - one at a time.

I almost always use WeakHashMap<K, WeakReference<V>> for that reason. Why would they not have made that the default behavior - values as weak references too?

回答1:

Reference queues are used to automatically remove entries.

http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/ref/ReferenceQueue.html

Reference queues, to which registered reference objects are appended by the garbage collector after the appropriate reachability changes are detected.

Basically, weak references are a core part of the garbage collector, so when a GC sweep happens, unused references are found and put onto queues and then action can be taken based on the content of those queues.

A thread can sit on the queue's remove method to be alerted when cleanup needs to be done or poll the queue.

"Java theory and practice: Plugging memory leaks with weak references" explains:

The implementation of WeakHashMap illustrates a common idiom with weak references -- that some internal object extends WeakReference.

...

WeakHashMap uses weak references for holding map keys, which allows the key objects to be garbage collected when they are no longer used by the application, and the get() implementation can tell a live mapping from a dead one by whether WeakReference.get() returns null. But this is only half of what is needed to keep a Map's memory consumption from increasing throughout the lifetime of the application; something must also be done to prune the dead entries from the Map after the key object has been collected. Otherwise, the Map would simply fill up with entries corresponding to dead keys. And while this would be invisible to the application, it could still cause the application to run out of memory because the Map.Entry and value objects would not be collected, even if the key is.

...

Reference queues are the garbage collector's primary means of feeding back information to the application about object lifecycle. Weak references have two constructors: one takes only the referent as an argument and the other also takes a reference queue. When a weak reference has been created with an associated reference queue and the referent becomes a candidate for GC, the reference object (not the referent) is enqueued on the reference queue after the reference is cleared. The application can then retrieve the reference from the reference queue and learn that the referent has been collected so it can perform associated cleanup activities, such as expunging the entries for objects that have fallen out of a weak collection. (Reference queues offer the same dequeuing modes as BlockingQueue -- polled, timed blocking, and untimed blocking.)

EDIT:

Even with queues, weak maps can still leak. Ephemerons are an attempt to solve the case where a weak key references a strongly held value that references the key. They are not implementable in java.

Ephemerons solve a problem which is commonly found when trying to "attach" properties to objects by using a registry. When some property should be attached to an object, the property should (in terms of GC behavior) typically have the life-time that an instance variable of this object would have. However, this is complicated by having an external association between the object and its property such as:

property --------- registry --------- association --------- object

Here, the registry (a third party) will hold onto the association itself which would require manual removal from the registry (instead of automated garbage collection). While this problem can always be solved in any given concrete situation by using one of the various weak association types, choosing the 'right' kind of association depends on a variety of factors some of which can change dynamically.

Ephemerons solve this problem by defining that the 'contents' (value) of an ephemeron will be held strongly until the key is known to be garbage collected. From then on, the contents of the ephemeron will be held weakly. Therefore, the contents of an ephemeron can become eligible for garbage collection if and only if the key is garbage collectable which is the exact behavior which we would observe for an instance variable of the object.