Summary
Add new java.lang.ref.Reference::refersTo
method.
Problem
There is a frequently occurring need to determine whether a Reference (still) refers to a given object, or whether it has been (possibly automatically) cleared.
Sometimes automatic clearing detection is accomplished via the use of
a ReferenceQueue
, and noticing when the Reference
shows up there.
However, that's not always convenient.
It also doesn't support testing whether some non-null object is the
referent. That use-case arises, for example, when looking up an object
in a weak-keyed hash table, where keys in a possible collision chain
need to be compared to the object being looked up. One way to solve
that is to use Reference::get
and compare the result with the value of
interest. However, such use of Reference::get
interacts poorly with
some GCs. Reference::get
returns a strong reference to the referent. In
order to ensure collector invariants are maintained and live objects
are not incorrectly discarded, some collectors may treat a referent
accessed by Reference::get
as strongly reachable until some later
collection cycle. When using such a collector, repeated checks using
Reference::get
could prevent a reference from ever being cleared,
even though its referent object is only (weakly) reachable from the
reference and occasionally, briefly, while performing those repeated
checks.
Also, such use of Reference::get
only works for SoftReference
and
WeakReference;
it does not work for PhantomReference
, whose
referent is inaccessible. And for SoftReferences
it has the
problem of introducing a recent access, potentially extending the
lifetime of the referent for all collectors.
Solution
The proposed solution is to add a new
java.lang.ref.Reference::refersTo(Object o)
method, which returns true if the
given object is the same as the referent where o can be null to test if this reference has been cleared.
Specification
The specification of refersTo:
/**
* Tests if the referent of this reference object is {@code obj}.
* Using a {@code null} {@code obj} returns {@code true} if the
* reference object has been cleared.
*
* @param obj the object to compare with this reference object's referent
* @return {@code true} if {@code obj} is the referent of this reference object
* @since 16
*/
public final boolean refersTo(T obj)
In addition, add the following API note to Reference.get:
* @apiNote
* This method returns a strong reference to the referent. This may cause
* the garbage collector to treat it as strongly reachable until some later
* collection cycle. The {@link #refersTo(Object) refersTo} method can be
* used to avoid such strengthening when testing whether some object is
* the referent of a reference object; that is, use {@code ref.refersTo(obj)}
* rather than {@code ref.get() == obj}.
*
* @return The object to which this reference refers, or
* {@code null} if this reference object has been cleared
* @see refersTo
Alternatives
An alternative to the proposed new function would be to have the compiler intrinsify Reference.get, recognizing non-escaping uses that are compared to some other object. Such idiomatic usage could be transformed into a form that doesn't treat the referent as strongly reachable. However, relying on an optimization to produce such an application-visible behavior seems questionable. It seems better to require explicit intent via use of the new function.
- csr of
-
JDK-8188055 (ref) Add Reference::refersTo predicate
- Resolved