Navigation Menu

Skip to content

Commit

Permalink
8071507: (ref) Clear phantom reference as soft and weak references do
Browse files Browse the repository at this point in the history
8143847: Remove REF_CLEANER reference category

Reviewed-by: mchung, kbarrett, iris
  • Loading branch information
Poonam Bajaj committed Apr 28, 2022
1 parent d63ed0a commit ad6cdea
Show file tree
Hide file tree
Showing 10 changed files with 122 additions and 65 deletions.
3 changes: 1 addition & 2 deletions hotspot/src/share/vm/classfile/systemDictionary.cpp
Expand Up @@ -1907,12 +1907,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);

// JSR 292 classes
WKID jsr292_group_start = WK_KLASS_ENUM_NAME(MethodHandle_klass);
Expand Down
1 change: 0 additions & 1 deletion hotspot/src/share/vm/classfile/systemDictionary.hpp
Expand Up @@ -128,7 +128,6 @@ class Ticks;
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(Thread_klass, java_lang_Thread, Pre ) \
Expand Down
1 change: 0 additions & 1 deletion hotspot/src/share/vm/classfile/vmSymbols.hpp
Expand Up @@ -79,7 +79,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_reflect_AccessibleObject, "java/lang/reflect/AccessibleObject") \
template(java_lang_reflect_Method, "java/lang/reflect/Method") \
Expand Down
26 changes: 1 addition & 25 deletions hotspot/src/share/vm/memory/referenceProcessor.cpp
Expand Up @@ -118,7 +118,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 @@ -245,14 +244,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, false,
process_discovered_reflist(_discoveredPhantomRefs, NULL, true,
is_alive, keep_alive, complete_gc, task_executor);
}

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

size_t
Expand Down Expand Up @@ -1051,9 +1042,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 @@ -1319,17 +1307,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 @@ -1398,7 +1375,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
3 changes: 1 addition & 2 deletions hotspot/src/share/vm/memory/referenceProcessor.hpp
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
3 changes: 1 addition & 2 deletions hotspot/src/share/vm/memory/referenceType.hpp
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 @@ -671,7 +671,6 @@ typedef BinaryTreeDictionary<Metablock, FreeList<Metablock> > MetablockTreeDicti
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");
}
}
}

1 comment on commit ad6cdea

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.