<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Jan 22, 2016, at 2:49 PM, Peter Levart <<a href="mailto:peter.levart@gmail.com" class="">peter.levart@gmail.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class="">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" class="">
<div style="background-color: rgb(255, 255, 255);" bgcolor="#FFFFFF" text="#000000" class="">
Hi Gil,<br class="">
<br class="">
Thanks for taking a look at the Ephemerons for Java. It's great to
have a big mind joining the discussion.<br class="">
<br class="">
<div class="moz-cite-prefix">On 01/22/2016 07:12 PM, Gil Tene wrote:<br class="">
</div>
<blockquote cite="mid:7E94B627-1D98-42A6-A5C9-788E6092A5D0@azul.com" type="cite" class=""><!--[if !IE]><DIV style="border-left: 2px solid #009900; border-right: 2px solid #009900; padding: 0px 15px; margin: 2px 0px;"><![endif]-->
<pre wrap="" class="">Peter,
I've been following Ephemerons in other GC'ed environments, and wondering when someone will bring it up for Java. Happy to see attentions given to it. The "conditional weak reference hashmap/table/dictionary" use case seems to be a common primary motivator, and it's a very valid one. Given that we currently do completely concurrent ref processing (in Zing at least) for all reference types, adding Ephemerons to the spec'ed behavior will add some interesting challenges for keeping things concurrent, but I don't think that it is fundamentally undoable (just "hard" and interesting to fully work out).</pre>
<!--[if !IE]></DIV><![endif]--></blockquote>
<br class="">
The algorithm for processing ephemerons is not much different from
that for processing normal references. It's just that it is
iterative until it converges to a stable state. If you allow mutator
threads to at least in some phases execute concurrently with normal
reference processing then I suspect it should be possible to do that
for ephemerons too, but I don't have a clue what tricks you perform
to be able to allow mutator threads to be concurrent with reference
processing.<br class="">
<br class="">
<blockquote cite="mid:7E94B627-1D98-42A6-A5C9-788E6092A5D0@azul.com" type="cite" class=""><!--[if !IE]><DIV style="border-left: 2px solid #009900; border-right: 2px solid #009900; padding: 0px 15px; margin: 2px 0px;"><![endif]-->
<pre wrap="" class="">Scanning through the proposal and Java class (mostly JavaDoc spec), I have the following question:
Do we really need a separate "ephemerally reachable" strength below week? The was you extended the definition to the weak definition to say "An object is weakly reachable if it is neither strongly nor softly reachable but can be reached by traversing a weak reference or by traversing an ephemeron through it's value while the ephemeron's key is at least weakly reachable." would [naively] seem to be sufficient to add and fully describe the desired Ephemeron behavior from a reference strength perspective.</pre>
<!--[if !IE]></DIV><![endif]--></blockquote>
<br class="">
Ephemeron always touches definitions of at least two consecutive
strengths of reachabilities. The prototype says:<br class="">
<br class="">
* <li> An object is <em>weakly reachable</em> if
it is neither<br class="">
* strongly nor softly reachable but can be reached by traversing a<br class="">
* weak reference or by traversing an ephemeron through it's value
while<br class="">
* the ephemeron's key is at least weakly reachable.<br class="">
<br class="">
* <li> An object is <em>ephemerally
reachable</em> if it is neither<br class="">
* strongly, softly nor weakly reachable but can be reached by
traversing an<br class="">
* ephemeron through it's key or by traversing an ephemeron through
it's value<br class="">
* while it's key is at most ephemerally reachable. When the
ephemerons that<br class="">
* refer to ephemerally reachable key object are cleared, the key
object becomes<br class="">
* eligible for finalization.<br class=""></div></div></blockquote><div><br class=""></div><div>Looking into this a bit more, I don't think the above is quite right. Specifically, If an ephemeron's key is either strongly of softly reachable, you want the value to remain appropriately strongly/softly reachable. Without this quality, Ephemeron value referents can (and will) be prematurely collected and finalized while the keys are not. This (IMO) needed quality not provided by the behavior you specify… </div><div><br class=""></div><div>For a correctly specified behavior, I think all strengths (from strong down) need to be affected by key/value Ephemeron relationships, but without adding an "ephemerally reachable" strength. E.g. I think you fundamentally need something like this:</div><div><br class=""></div><div>- "An object is <em>strongly reachable</em> if it can be reached by (a) some thread without traversing any reference objects, or by (b) traversing the value of an Ephemeron whose key is strongly reachable. A newly-created object is strongly reachable by the thread that created it"</div><div><br class=""></div><div>- "An object is <em>softly reachable</em> if it is not strongly reachable but can be reached by (a) traversing a soft reference or by (b) traversing the value of an Ephemeron whose key is softly reachable.</div><div><br class=""></div><div><div>- "An object is <em>weakly reachable</em> if it is neither strongly nor softly reachable but can be reached by (a) traversing a weak reference or by (b) traversing the value of an ephemeron whose key is weakly reachable.</div><div><br class=""></div></div><blockquote type="cite" class=""><div class=""><div style="background-color: rgb(255, 255, 255);" bgcolor="#FFFFFF" text="#000000" class="">
<br class="">
But Ephemeron does not need a special reachability strength. It
could be merged with WeakReference as far as the reachability of
it's key is concerned. In that case it would touch at least the
definitions of softly-reachable and weakly-reachable:<br class="">
<br class="">
* <li> An object is <em>softly reachable</em> if
it is not strongly<br class="">
* reachable but can be reached by traversing a soft reference or <br class="">
* by traversing an ephemeron through it's value while<br class="">
* the ephemeron's key is at least softly reachable.<br class="">
<br class="">
* <li> An object is <em>weakly reachable</em> if
it is neither<br class="">
* strongly nor softly reachable but can be reached by traversing a<br class="">
* weak reference (including ephemeron through it's key) or by
traversing<br class="">
* an ephemeron through it's value while the ephemeron's key is at
most <br class="">
* weakly reachable. When the weak references to a weakly-reachable<br class="">
* object are cleared (which includes ephemerons to a
weakly-reachable key), <br class="">
* the object becomes eligible for finalization.<br class="">
<br class="">
<br class="">
Presently the hotspot handles different strengths of references by
maintaining a distinct set of discovered references for each type
and then processing these sets in sequence from the strongest to the
weakest. If Ephemerons and WeakReferences were kept in the same
discovered set, they would present the same reachability strength
for their referent (called also the key in case of ephemeron).<br class="">
<br class="">
<blockquote cite="mid:7E94B627-1D98-42A6-A5C9-788E6092A5D0@azul.com" type="cite" class=""><!--[if !IE]><DIV style="border-left: 2px solid #009900; border-right: 2px solid #009900; padding: 0px 15px; margin: 2px 0px;"><![endif]-->
<pre wrap="" class="">Specifically, would modifying your implementation such that Ephemeron<K, V> extended WeakReference<K> (instead of Reference<K>), and it's V value was tracked with "private WeakReference<V> valueRef" (instead of "private V value") [along with the semi-obvious internal changes that would result] provide what is needed to support proper Ephemeron behavior we just added the "…or by traversing an ephemeron through it's value while the ephemeron's key is at least weakly reachable." to the spec'ed definition of "weakly reachable" (and modified the associated JVM ref processing accordingly, which you already have to do to support your wider definitions anyway)?</pre>
<!--[if !IE]></DIV><![endif]--></blockquote>
<br class="">
In case the strength of ephemeron's key was the same as that of
WeakReference's referent, it would make sense for Ephemeron to
extend WeakReference, since it would then just be a special kind of
WeakReference. But I don't think that changing "private V value"
into "private WeakReference<V> valueRef" would buy anything in
terms of processing algorithm simplicity. At least in hotspot it
would increase the code complexity, since marking the ephemeron's
value 'alive' as a consequence of finding it's key marked alive
during iteration over the list of ephemerons and removing the
current ephemeron from the pending list, would also require removing
of the valuRef WeakReference from the pending list at the same time
but that would require finding it in the list 1st, since it's a
single-linked-list or removing it at next iteration which would
increase the number of iterations through the pending set before the
state converges...<br class="">
<br class="">
There's no problem in making the VM to treat the "private V value"
specially. In HotSpot it is only required to update the OopMap for
the Ephemeron class to exclude the value field - analogue to how
this is done for Reference fields. There's no need for indirection
through another WeakReference to get special treatment for value
(exclusion from traversals).<br class=""></div></div></blockquote><div><br class=""></div>I agree that the value fields does not need to be a Weakref, and the a "private V value; /* Treated specially by GC */" can be used (much like Reference's declaration of the referent field). So I take back my suggestion on that.</div><div><br class=""></div><div>I still think that Ephemeron<K, V> should extend WeakReference<K>, since that places already established rules and expectation on (a) when it will be enqueued, (b) when the collector will clear it (when the the collector encounters the <K> key being weakly reachable), and (c) that clearing of all Ephemeron *and* WeakReference instances who share an identical key value is done atomically, along with (d) all weak references to to any other weakly-reachable objects from which that object is reachable through a chain of strong and soft references. These last (c, d) parts are critically captured since an Ephemeron *is a* WeakReference, and the statement in WeakReference that says that "… it will atomically clear all weak references to that object and all weak references to any other weakly-reachable objects from which that object is reachable through a chain of strong and soft references." has a clear application.</div><div><br class=""></div><div>Here are some suggested edits to the JavaDoc to go with this suggested spec'ed behavior:</div><div><div class="">/**</div><div class=""> * Ephemeron<K, V> objects are a special kind of WeakReference<K> objects, which</div><div class=""> * hold two referents (a key referent and a value referent) and do not prevent their</div><div class=""> * referents from being made finalizable, finalized, and then reclaimed.</div><div class=""> * In addition to the key referent, which adheres to the referent behavior of a</div><div class=""> * WeakReference<K>, an ephemeron also holds a value referent whose reachabiliy</div><div class=""> * strength is affected by the reachability strength of the key referent: </div><div class=""> * The value referent of an Ephemeron instance is considered:</div><div class=""> * (a) strongly reachable if the key referent of the same Ephemeron</div><div class=""> * object is strongly reachable, or if the value referent is otherwise strongly reachable.</div><div class=""><div class=""> * (b) softly reachable if it is not strongly reachable, and (i) the key referent of</div><div class=""> * the same Ephemeron object is softly reachable, or (ii) if the value referent is otherwise</div><div class=""> * softly reachable.</div></div><div class=""><div class=""> * (c) weakly reachable if it is not strongly or softly reachable, and (i) the key referent of</div><div class=""> * the same Ephemeron object is weakly reachable, or (ii) if the value referent is otherwise</div><div class=""> * weakly reachable.</div></div><div class=""> * <p> When the collector clears an Ephemeron object instance (according to the rules</div></div><div><div class=""> * expressed for clearing WeakReference object instances), the Ephemeron instance's</div><div class=""> * key referent value referent are simultaneously and atomically cleared.</div><div class=""> * <p> By convenience, the Ephemeron's referent is also called the key, and can be</div><div class=""> * obtained either by invoking {@link #get} or {@link #getKey} while the value</div><div class=""> * can be obtained by invoking {@link #getValue} method.</div><div class=""> *...</div><div class=""><br class=""></div></div><div><br class=""></div><div><blockquote type="cite" class=""><div class=""><div style="background-color: rgb(255, 255, 255);" bgcolor="#FFFFFF" text="#000000" class="">
<br class="">
Regards, Peter<br class="">
<br class="">
<br class="">
<br class="">
— Gil.
<blockquote cite="mid:7E94B627-1D98-42A6-A5C9-788E6092A5D0@azul.com" type="cite" class=""><!--[if !IE]><DIV style="border-left: 2px solid #009900; border-right: 2px solid #009900; padding: 0px 15px; margin: 2px 0px;"><![endif]-->
<blockquote type="cite" class=""><!--[if !IE]><DIV style="border-left: 2px solid #009900; border-right: 2px solid #009900; padding: 0px 15px; margin: 2px 0px;"><![endif]-->
<pre wrap="" class="">On Jan 17, 2016, at 10:18 AM, Peter Levart <a class="moz-txt-link-rfc2396E" href="mailto:peter.levart@gmail.com"><peter.levart@gmail.com></a> wrote:
Hi,
Ephemerons are special kind of references described by Barry Hayes [1]. In the simple variant, they contain two "referents". One is called the key, which can be viewed as a "weak" referent in the style of Java reference types (SoftReference, WeakReference, PhantomReference), the other is called the value, which is also treated specially by GC. It's reachability is dependent on the reachability of the key.
Ephemerons solve the problem seen for example in the java.util.WeakHashMap when a value in this map directly or indirectly refers to it's key. Such entry will never be purged as the value is always reachable from the WeakHashMap instance and through the value, it's key is reachable too. There are other places where Ephemerons could be used - for example in ClassValue API. Try googling for "java ephemeron" (without quotes) to find out other situations where Ephemerons would be beneficial.
If one was to implement Ephemerons in Java, the main question he would be asking is how Ephemeron(s) were supposed to interact with existing Java reference types. Hayes only defines their behavior in isolation, but Java already has 4 "weak" reference types with different "strengths": SoftReference, WeakReference, FinalReference (for implementing finalization) and PhantomReference. In the prototype I choose to define Ephemerons as a new reference type with it's own "strength" for the key referent positioned between WeakReference and FinalReference. It would be possible to merge it with an existing reference type like WeakReference or position it between SoftReference and WeakReference or even entirely "on the top" of the strength list, but I think it would not be wise to position it below FinalReference or even PhantomReference. What's best is an open question. What is also not so obvious is how to define the reachability of the Ephemeron's value and it's interaction with exis
ting refe
rence types. I think I defined it soundly (see the reachability types in the javadoc of [4]). The reason for defining the reachability of the value to alternate between ephemeraly-reachable and weakly-reachable and not between ephemeraly-reachable and strongly-reachable, while theoretically possible, is the desire to have a separate phase of processing for each reachability strength, like it is done currently, and which doesn't affect the performance of processing of existing reference types.
Having skimmed through the reference processing code in the VM for a couple of times, I thought it should not be too complicated to implement another type of "weak" reference. Encouraged by how little changes were needed to remove the sun.misc.Cleaner special type of reference [2], I began experimenting and came up with a prototype that seems to work [3]. Luckily most of the logic to process Reference objects in VM is encapsulated in the ReferenceProcessor class and this logic is invoked from various GC implementations of the hotspot. Changes needed are therefore mostly localized to this class. The webrev also contains recent changes from JDK-8143847 [2] that have not yet propagated to the jdk9-dev repo. When they do, I will prepare a rebased webrev without those changes.
I'm publishing this prototype here to get the answer to the main question: Is there an interest to have Ephemeron reference type in Java?
Given that there was interest, I would also like to initiate a discussion about:
- What would be the most appropriate "strength" of reachabillity for Epehmeron referents (key and value) and the desired interactions with existing reachabilities.
- The prototype itself. Since I'm new to this part of code (that's my 1st not so shallow dive into the VM), I surely must have missed places that should be changed. Although the prototype seems to work, I have not created extensive tests for the functionality and have not exposed it to all the various GC algorithms and situations yet. I could use some advise on how to exercise all GC algorithm combinations possible in the VM (what flags to use, for example).
Regards, Peter
[1] <a class="moz-txt-link-freetext" href="https://static.aminer.org/pdf/PDF/000/522/273/ephemerons_a_new_finalization_mechanism.pdf">https://static.aminer.org/pdf/PDF/000/522/273/ephemerons_a_new_finalization_mechanism.pdf</a>
[2] <a class="moz-txt-link-freetext" href="https://bugs.openjdk.java.net/browse/JDK-8143847">https://bugs.openjdk.java.net/browse/JDK-8143847</a>
[3] <a class="moz-txt-link-freetext" href="http://cr.openjdk.java.net/~plevart/misc/Ephemeron/">http://cr.openjdk.java.net/~plevart/misc/Ephemeron/</a>
[4] <a class="moz-txt-link-freetext" href="http://cr.openjdk.java.net/~plevart/misc/Ephemeron/webrev.jdk.01/src/java.base/share/classes/java/lang/ref/Ephemeron.java.html">http://cr.openjdk.java.net/~plevart/misc/Ephemeron/webrev.jdk.01/src/java.base/share/classes/java/lang/ref/Ephemeron.java.html</a>
P.S.
To wet some appetite, with the above prototype (applied to current jdk9-dev), it is possible to run the following example:
import java.lang.ref.Ephemeron;
import java.util.ArrayList;
import java.util.List;
public class EphemeronTest {
static class Key {
final int i;
Key(int i) {
this.i = i;
}
@Override
public String toString() {
return "k" + i;
}
}
static class Value {
final Key key;
Value(Key key) {
this.key = key;
}
@Override
public String toString() {
return "v(" + key + ")";
}
}
static class Eph extends Ephemeron<Key, Value> {
public Eph(Key key, Value value) {
super(key, value);
}
@Override
public String toString() {
return getKey() + "=" + getValue();
}
}
static void test(int size, boolean forwardChaining) throws Exception {
System.out.println();
System.out.println((forwardChaining ? "Forward" : "Backward") +
" chaining of value->key ...");
System.out.println();
List<Eph> ephs = new ArrayList<>(size);
Key k1 = new Key(1);
{
Key kp = k1;
for (int i = 2; i <= size; i++) {
Key ki = new Key(i);
ephs.add(
forwardChaining
? new Eph(kp, new Value(ki))
: new Eph(ki, new Value(kp))
);
kp = ki;
}
ephs.add(
forwardChaining
? new Eph(kp, new Value(k1))
: new Eph(k1, new Value(kp))
);
kp = null;
}
System.gc();
System.out.println("1: " + ephs);
k1.getClass(); // reachabilityFence
k1 = null;
System.gc();
System.out.println("2: " + ephs);
}
public static void main(String[] args) throws Exception {
int size = (args.length < 1)
? 5
: Math.max(2, Integer.parseInt(args[0]));
test(size, true);
test(size, false);
}
}
Which prints:
Forward chaining of value->key ...
1: [k1=v(k2), k2=v(k3), k3=v(k4), k4=v(k5), k5=v(k1)]
2: [null=null, null=null, null=null, null=null, null=null]
Backward chaining of value->key ...
1: [k2=v(k1), k3=v(k2), k4=v(k3), k5=v(k4), k1=v(k5)]
2: [null=null, null=null, null=null, null=null, null=null]
If you compile the JDK with --enable-debug and use the following VM switches when running: -XX:+PrintGCDetails -XX:+TraceReferenceGC, you can also observe the inner workings of the reference processing, including Ephemerons.
</pre>
<!--[if !IE]></DIV><![endif]--></blockquote>
<pre wrap="" class=""></pre>
<!--[if !IE]></DIV><![endif]--></blockquote>
<br class="">
</div>
</div></blockquote></div><br class=""></body></html>