Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8071507: (ref) Clear phantom reference as soft and weak references do #94

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 1 addition & 2 deletions hotspot/src/share/vm/classfile/systemDictionary.cpp
Expand Up @@ -2025,12 +2025,11 @@ void SystemDictionary::initialize_preloaded_classes(TRAPS) {
InstanceKlass::cast(WK_KLASS(Reference_klass))->set_reference_type(REF_OTHER);
InstanceRefKlass::update_nonstatic_oop_maps(WK_KLASS(Reference_klass));

initialize_wk_klasses_through(WK_KLASS_ENUM_NAME(Cleaner_klass), scan, CHECK);
initialize_wk_klasses_through(WK_KLASS_ENUM_NAME(PhantomReference_klass), scan, CHECK);
InstanceKlass::cast(WK_KLASS(SoftReference_klass))->set_reference_type(REF_SOFT);
InstanceKlass::cast(WK_KLASS(WeakReference_klass))->set_reference_type(REF_WEAK);
InstanceKlass::cast(WK_KLASS(FinalReference_klass))->set_reference_type(REF_FINAL);
InstanceKlass::cast(WK_KLASS(PhantomReference_klass))->set_reference_type(REF_PHANTOM);
InstanceKlass::cast(WK_KLASS(Cleaner_klass))->set_reference_type(REF_CLEANER);

initialize_wk_klasses_through(WK_KLASS_ENUM_NAME(ReferenceQueue_klass), scan, CHECK);

Expand Down
1 change: 0 additions & 1 deletion hotspot/src/share/vm/classfile/systemDictionary.hpp
Expand Up @@ -127,7 +127,6 @@ class SymbolPropertyTable;
do_klass(WeakReference_klass, java_lang_ref_WeakReference, Pre ) \
do_klass(FinalReference_klass, java_lang_ref_FinalReference, Pre ) \
do_klass(PhantomReference_klass, java_lang_ref_PhantomReference, Pre ) \
do_klass(Cleaner_klass, sun_misc_Cleaner, Pre ) \
do_klass(Finalizer_klass, java_lang_ref_Finalizer, Pre ) \
do_klass(ReferenceQueue_klass, java_lang_ref_ReferenceQueue, Pre ) \
\
Expand Down
1 change: 0 additions & 1 deletion hotspot/src/share/vm/classfile/vmSymbols.hpp
Expand Up @@ -80,7 +80,6 @@
template(java_lang_ref_WeakReference, "java/lang/ref/WeakReference") \
template(java_lang_ref_FinalReference, "java/lang/ref/FinalReference") \
template(java_lang_ref_PhantomReference, "java/lang/ref/PhantomReference") \
template(sun_misc_Cleaner, "sun/misc/Cleaner") \
template(java_lang_ref_Finalizer, "java/lang/ref/Finalizer") \
template(java_lang_ref_ReferenceQueue, "java/lang/ref/ReferenceQueue") \
template(java_lang_reflect_AccessibleObject, "java/lang/reflect/AccessibleObject") \
Expand Down
28 changes: 2 additions & 26 deletions hotspot/src/share/vm/memory/referenceProcessor.cpp
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2016, 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
Expand Down Expand Up @@ -121,7 +121,6 @@ ReferenceProcessor::ReferenceProcessor(MemRegion span,
_discoveredWeakRefs = &_discoveredSoftRefs[_max_num_q];
_discoveredFinalRefs = &_discoveredWeakRefs[_max_num_q];
_discoveredPhantomRefs = &_discoveredFinalRefs[_max_num_q];
_discoveredCleanerRefs = &_discoveredPhantomRefs[_max_num_q];

// Initialize all entries to NULL
for (uint i = 0; i < _max_num_q * number_of_subclasses_of_ref(); i++) {
Expand Down Expand Up @@ -248,14 +247,7 @@ ReferenceProcessorStats ReferenceProcessor::process_discovered_references(
{
GCTraceTime tt("PhantomReference", trace_time, false, gc_timer, gc_id);
phantom_count =
process_discovered_reflist(_discoveredPhantomRefs, NULL, false,
is_alive, keep_alive, complete_gc, task_executor);

// Process cleaners, but include them in phantom statistics. We expect
// Cleaner references to be temporary, and don't want to deal with
// possible incompatibilities arising from making it more visible.
phantom_count +=
process_discovered_reflist(_discoveredCleanerRefs, NULL, true,
process_discovered_reflist(_discoveredPhantomRefs, NULL, true,
is_alive, keep_alive, complete_gc, task_executor);
}

Expand Down Expand Up @@ -889,7 +881,6 @@ void ReferenceProcessor::balance_all_queues() {
balance_queues(_discoveredWeakRefs);
balance_queues(_discoveredFinalRefs);
balance_queues(_discoveredPhantomRefs);
balance_queues(_discoveredCleanerRefs);
}

size_t
Expand Down Expand Up @@ -1049,9 +1040,6 @@ inline DiscoveredList* ReferenceProcessor::get_discovered_list(ReferenceType rt)
case REF_PHANTOM:
list = &_discoveredPhantomRefs[id];
break;
case REF_CLEANER:
list = &_discoveredCleanerRefs[id];
break;
case REF_NONE:
// we should not reach here if we are an InstanceRefKlass
default:
Expand Down Expand Up @@ -1317,17 +1305,6 @@ void ReferenceProcessor::preclean_discovered_references(
preclean_discovered_reflist(_discoveredPhantomRefs[i], is_alive,
keep_alive, complete_gc, yield);
}

// Cleaner references. Included in timing for phantom references. We
// expect Cleaner references to be temporary, and don't want to deal with
// possible incompatibilities arising from making it more visible.
for (uint i = 0; i < _max_num_q; i++) {
if (yield->should_return()) {
return;
}
preclean_discovered_reflist(_discoveredCleanerRefs[i], is_alive,
keep_alive, complete_gc, yield);
}
}
}

Expand Down Expand Up @@ -1396,7 +1373,6 @@ const char* ReferenceProcessor::list_name(uint i) {
case 1: return "WeakRef";
case 2: return "FinalRef";
case 3: return "PhantomRef";
case 4: return "CleanerRef";
}
ShouldNotReachHere();
return NULL;
Expand Down
5 changes: 2 additions & 3 deletions hotspot/src/share/vm/memory/referenceProcessor.hpp
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2016, 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
Expand Down Expand Up @@ -264,10 +264,9 @@ class ReferenceProcessor : public CHeapObj<mtGC> {
DiscoveredList* _discoveredWeakRefs;
DiscoveredList* _discoveredFinalRefs;
DiscoveredList* _discoveredPhantomRefs;
DiscoveredList* _discoveredCleanerRefs;

public:
static int number_of_subclasses_of_ref() { return (REF_CLEANER - REF_OTHER); }
static int number_of_subclasses_of_ref() { return (REF_PHANTOM - REF_OTHER); }

uint num_q() { return _num_q; }
uint max_num_q() { return _max_num_q; }
Expand Down
5 changes: 2 additions & 3 deletions hotspot/src/share/vm/memory/referenceType.hpp
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2016, 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
Expand Down Expand Up @@ -35,8 +35,7 @@ enum ReferenceType {
REF_SOFT, // Subclass of java/lang/ref/SoftReference
REF_WEAK, // Subclass of java/lang/ref/WeakReference
REF_FINAL, // Subclass of java/lang/ref/FinalReference
REF_PHANTOM, // Subclass of java/lang/ref/PhantomReference
REF_CLEANER // Subclass of sun/misc/Cleaner
REF_PHANTOM // Subclass of java/lang/ref/PhantomReference
};

#endif // SHARE_VM_MEMORY_REFRERENCETYPE_HPP
1 change: 0 additions & 1 deletion hotspot/src/share/vm/runtime/vmStructs.cpp
Expand Up @@ -673,7 +673,6 @@ typedef TwoOopHashtable<Symbol*, mtClass> SymbolTwoOopHashtable;
static_field(SystemDictionary, WK_KLASS(WeakReference_klass), Klass*) \
static_field(SystemDictionary, WK_KLASS(FinalReference_klass), Klass*) \
static_field(SystemDictionary, WK_KLASS(PhantomReference_klass), Klass*) \
static_field(SystemDictionary, WK_KLASS(Cleaner_klass), Klass*) \
static_field(SystemDictionary, WK_KLASS(Finalizer_klass), Klass*) \
static_field(SystemDictionary, WK_KLASS(Thread_klass), Klass*) \
static_field(SystemDictionary, WK_KLASS(ThreadGroup_klass), Klass*) \
Expand Down
25 changes: 11 additions & 14 deletions jdk/src/share/classes/java/lang/ref/PhantomReference.java
@@ -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
Expand Down Expand Up @@ -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</code> method of a
* phantom reference always returns <code>null</code>.
*
* <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
*/
Expand All @@ -69,8 +66,8 @@ public T get() {
*
* <p> It is possible to create a phantom reference with a <tt>null</tt>
* queue, but such a reference is completely useless: Its <tt>get</tt>
* 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,
Expand Down
23 changes: 6 additions & 17 deletions jdk/src/share/classes/java/lang/ref/package.html
@@ -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
Expand Down Expand Up @@ -46,8 +46,7 @@ <h2>Package Specification</h2>
references are for 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.
post-mortem cleanup actions.

<p> Each reference-object type is implemented by a subclass of the abstract
base <code>{@link java.lang.ref.Reference}</code> class. An instance of one of
Expand All @@ -66,9 +65,10 @@ <h3>Notification</h3>
<em>registering</em> an appropriate reference 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 references from a queue either
to the 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 <code>{@link java.lang.ref.ReferenceQueue}</code>
class.
Expand All @@ -91,17 +91,6 @@ <h3>Notification</h3>
checks an internal data 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>

Expand Down
101 changes: 101 additions & 0 deletions jdk/test/java/lang/ref/PhantomReferentClearing.java
@@ -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");
}
}
}