# HG changeset patch # User kbarrett # Date 1451329419 18000 # Node ID 87b434f45259a7092be4e4c2c1a5b66594f7c188 # Parent 9b8d97b835202eac51fe0835a98d113b6a50c7c9 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 diff -r 9b8d97b83520 -r 87b434f45259 jdk/src/java.base/share/classes/java/lang/ref/PhantomReference.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. * - *

If the garbage collector determines at a certain point in time that the - * referent of a phantom reference is phantom reachable, then at that - * time or at some later time it will enqueue the reference. + *

Suppose the garbage collector determines at a certain point in time + * that an object is + * phantom reachable. 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. * *

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}. * - *

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 @@ * *

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, diff -r 9b8d97b83520 -r 87b434f45259 jdk/src/java.base/share/classes/java/lang/ref/package-info.java --- 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. * *

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 reference queue 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 enqueued. 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 enqueued. 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. * - *

Automatically-cleared references

- * - * 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. - * * *

Reachability

* diff -r 9b8d97b83520 -r 87b434f45259 jdk/test/java/lang/ref/PhantomReferentClearing.java --- /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 Q1 = new ReferenceQueue<>(); + private static final ReferenceQueue Q2 = new ReferenceQueue<>(); + + private static volatile Object O2 = new Object(); + private static volatile List O1 = new ArrayList<>(); + static { + O1.add(O2); + } + + private static final PhantomReference P1 = new PhantomReference<>(O1, Q1); + private static final PhantomReference 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"); + } + } +}