8071507: (ref) Clear phantom reference as soft and weak references do
authorkbarrett
Mon, 28 Dec 2015 14:03:39 -0500
changeset 35265 87b434f45259
parent 35264 9b8d97b83520
child 35266 e18371fa3e76
8071507: (ref) Clear phantom reference as soft and weak references do Summary: GC clears phantom refs on notification; update spec accordingly. Reviewed-by: mchung, jmasa
jdk/src/java.base/share/classes/java/lang/ref/PhantomReference.java
jdk/src/java.base/share/classes/java/lang/ref/package-info.java
jdk/test/java/lang/ref/PhantomReferentClearing.java
--- a/jdk/src/java.base/share/classes/java/lang/ref/PhantomReference.java	Wed Dec 23 13:12:46 2015 +0300
+++ b/jdk/src/java.base/share/classes/java/lang/ref/PhantomReference.java	Mon Dec 28 14:03:39 2015 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,23 +29,20 @@
 /**
  * Phantom reference objects, which are enqueued after the collector
  * determines that their referents may otherwise be reclaimed.  Phantom
- * references are most often used for scheduling pre-mortem cleanup actions in
- * a more flexible way than is possible with the Java finalization mechanism.
+ * references are most often used to schedule post-mortem cleanup actions.
  *
- * <p> If the garbage collector determines at a certain point in time that the
- * referent of a phantom reference is <a
- * href="package-summary.html#reachability">phantom reachable</a>, then at that
- * time or at some later time it will enqueue the reference.
+ * <p> Suppose the garbage collector determines at a certain point in time
+ * that an object is <a href="package-summary.html#reachability">
+ * phantom reachable</a>.  At that time it will atomically clear
+ * all phantom references to that object and all phantom references to
+ * any other phantom-reachable objects from which that object is reachable.
+ * At the same time or at some later time it will enqueue those newly-cleared
+ * phantom references that are registered with reference queues.
  *
  * <p> In order to ensure that a reclaimable object remains so, the referent of
  * a phantom reference may not be retrieved: The {@code get} method of a
  * phantom reference always returns {@code null}.
  *
- * <p> Unlike soft and weak references, phantom references are not
- * automatically cleared by the garbage collector as they are enqueued.  An
- * object that is reachable via phantom references will remain so until all
- * such references are cleared or themselves become unreachable.
- *
  * @author   Mark Reinhold
  * @since    1.2
  */
@@ -69,8 +66,8 @@
      *
      * <p> It is possible to create a phantom reference with a {@code null}
      * queue, but such a reference is completely useless: Its {@code get}
-     * method will always return null and, since it does not have a queue, it
-     * will never be enqueued.
+     * method will always return {@code null} and, since it does not have a queue,
+     * it will never be enqueued.
      *
      * @param referent the object the new phantom reference will refer to
      * @param q the queue with which the reference is to be registered,
--- a/jdk/src/java.base/share/classes/java/lang/ref/package-info.java	Wed Dec 23 13:12:46 2015 +0300
+++ b/jdk/src/java.base/share/classes/java/lang/ref/package-info.java	Mon Dec 28 14:03:39 2015 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -43,8 +43,7 @@
  * implementing memory-sensitive caches, weak references are for
  * implementing canonicalizing mappings that do not prevent their keys
  * (or values) from being reclaimed, and phantom references are for
- * scheduling pre-mortem cleanup actions in a more flexible way than
- * is possible with the Java finalization mechanism.
+ * scheduling post-mortem cleanup actions.
  *
  * <p> Each reference-object type is implemented by a subclass of the
  * abstract base {@link java.lang.ref.Reference} class.
@@ -64,9 +63,9 @@
  * object with a <em>reference queue</em> at the time the reference
  * object is created.  Some time after the garbage collector
  * determines that the reachability of the referent has changed to the
- * value corresponding to the type of the reference, it will add the
- * reference to the associated queue.  At this point, the reference is
- * considered to be <em>enqueued</em>.  The program may remove
+ * value corresponding to the type of the reference, it will clear the
+ * reference and add it to the associated queue.  At this point, the
+ * reference is considered to be <em>enqueued</em>.  The program may remove
  * references from a queue either by polling or by blocking until a
  * reference becomes available.  Reference queues are implemented by
  * the {@link java.lang.ref.ReferenceQueue} class.
@@ -92,16 +91,6 @@
  * structure, this check will add little overhead to the hashtable
  * access methods.
  *
- * <h3>Automatically-cleared references</h3>
- *
- * Soft and weak references are automatically cleared by the collector
- * before being added to the queues with which they are registered, if
- * any.  Therefore soft and weak references need not be registered
- * with a queue in order to be useful, while phantom references do.
- * An object that is reachable via phantom references will remain so
- * until all such references are cleared or themselves become
- * unreachable.
- *
  * <a name="reachability"></a>
  * <h3>Reachability</h3>
  *
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/ref/PhantomReferentClearing.java	Mon Dec 28 14:03:39 2015 -0500
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8071507
+ * @summary Test that PhantomReferences are cleared when notified.
+ * @run main/othervm PhantomReferentClearing
+ */
+
+import java.lang.ref.PhantomReference;
+import java.lang.ref.ReferenceQueue;
+import java.util.ArrayList;
+import java.util.List;
+
+public class PhantomReferentClearing {
+
+    private static final long ENQUEUE_TIMEOUT = 1000;   // 1 sec, in millis
+
+    // P1 & P2 are PhantomReference objects
+    // O1 & O2 are objects
+    //
+    // -> is a strong reference
+    // => is a referent reference
+    //
+    //   root -> P1
+    //   root -> P2
+    //   root -> O1
+    //   root -> O2
+    //   O1 -> O2
+    //   P1 => O1
+    //   P2 => O2
+    //
+    // (1) Remove root -> O1 and collect.  P1 notified, P2 !notified.
+    // (2) Remove root -> O2 and collect.
+    //
+    // If phantom references are cleared when notified, as proposed by
+    // 8071507, then P2 should be notified, and the test passes.
+    //
+    // Otherwise, P2 does not get notified because it remains reachable
+    // from O1, which is being retained by P1.  This fails the test.
+
+    private static final ReferenceQueue<Object> Q1 = new ReferenceQueue<>();
+    private static final ReferenceQueue<Object> Q2 = new ReferenceQueue<>();
+
+    private static volatile Object O2 = new Object();
+    private static volatile List<Object> O1 = new ArrayList<>();
+    static {
+        O1.add(O2);
+    }
+
+    private static final PhantomReference<Object> P1 = new PhantomReference<>(O1, Q1);
+    private static final PhantomReference<Object> P2 = new PhantomReference<>(O2, Q2);
+
+    public static void main(String[] args) throws InterruptedException {
+
+        // Collect, and verify neither P1 or P2 notified.
+        System.gc();
+        if (Q1.remove(ENQUEUE_TIMEOUT) != null) {
+            throw new RuntimeException("P1 already notified");
+        } else if (Q2.poll() != null) {
+            throw new RuntimeException("P2 already notified");
+        }
+
+        // Delete root -> O1, collect, verify P1 notified, P2 not notified.
+        O1 = null;
+        System.gc();
+        if (Q1.remove(ENQUEUE_TIMEOUT) == null) {
+            throw new RuntimeException("P1 not notified by O1 deletion");
+        } else if (Q2.remove(ENQUEUE_TIMEOUT) != null) {
+            throw new RuntimeException("P2 notified by O1 deletion.");
+        }
+
+        // Delete root -> O2, collect. P2 should be notified.
+        O2 = null;
+        System.gc();
+        if (Q2.remove(ENQUEUE_TIMEOUT) == null) {
+            throw new RuntimeException("P2 not notified by O2 deletion");
+        }
+    }
+}