前言

最近 看到一篇文章, 然后 基于改文章的代码, 做了一些 调整, 然后 发现了一些 奇怪的事情, 并稍微整理了一下 原因

该文章地址 : https://hllvm-group.iteye.com/group/topic/34934

测试代码如下 :

package com.hx.test02;import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.reflect.Field;/*** Test02WeakReferenceAfterGc** @author Jerry.X.He <970655147@qq.com>* @version 1.0* @date 2019-10-14 11:23*/
public class Test02WeakReferenceAfterGc {// Test02WeakReferenceAfterGc// refer : https://hllvm-group.iteye.com/group/topic/34934public static void main(String[] args) throws Exception {ReferenceQueue<Obj> referenceQueue = new ReferenceQueue<>();for (int i = 0; i < 1; i++) {Obj o = new Obj("object_" + i);
//      SoftReference<Obj> ref = new SoftReference<>(o, referenceQueue);
//      WeakReference<Obj> ref = new WeakReference<>(o, referenceQueue);PhantomReference<Obj> ref = new PhantomReference<>(o, referenceQueue);o = null;System.gc();Field field = Reference.class.getDeclaredField("referent");field.setAccessible(true);System.out.println(field.get(ref));}// 这个现象, 有 finalize 和 没有 finalize 是两个不同的情况, 按照理论上来说[常规的思考], 有 finalize 的情况下, 应该会有两个 Reference 分别进入 两个队列, 但是没有Thread.sleep(3000);System.gc();// consumernew Thread() {public void run() {while (true) {Object o = referenceQueue.poll();if (o != null) {try {Field rereferent = Reference.class.getDeclaredField("referent");rereferent.setAccessible(true);Object result = rereferent.get(o);System.out.println("gc will collect : " + o.getClass() + "@" + o.hashCode() + ", referent : " + result);} catch (Exception e) {e.printStackTrace();}}}}}.start();}/*** Obj** @author Jerry.X.He <970655147@qq.com>* @version 1.0* @date 2019-10-14 11:24*/static class Obj {private final String name;Obj(String name) {this.name=name;}// test for FinalReference
//    @Override
//    protected void finalize() throws Throwable {
//      System.out.println("执行finalize方法:" + name);
//      super.finalize();
//    }@Overridepublic String toString() {return name;}}}

然后 我们这里 需要关注的主要的问题在于, Test02WeakReferenceAfterGc$Obj 在没有重写 finalize 方法的时候, 输出如下

object_0
gc will collect : class java.lang.ref.PhantomReference@1964850888, referent : object_0

在 Test02WeakReferenceAfterGc$Obj 重写了 finalize 方法之后 输出如下

object_0
执行finalize方法:object_0

这里 直观感觉就很奇怪了呀, 为什么 是否重写 finalize 方法, 会影响到 PhantomReference 进入对应的 引用队列呢 ?

针对重写 finalize 方法的情况讨论

最开始 我以为是 第一个 System.gc 之后,  Obj 的实例 o 对应的 FinalReferece 会引用该对象, 所以该 对象在gc的时候没有被清理, 所以 该 PhantomReference 没有被整理, 然后 上面的这段代码, 是我为了这个猜想增加的

        Thread.sleep(3000);System.gc();

但是, 发现 给定的 PhantomReference 还是没有  进入对应的引用队列

这个就很令人 疑惑了

测试代码均在jdk8下面编译, 以上测试代码结果, 运行于 jdk8, 一下部分代码, 截图基于 openjdk9

在 openjdk9 下面运行该测试方法, ref.get() 均为 null, 后面会提及到这一点的原因

以下描述 仅仅会描述一些和我们这里相关的部分, 整体的其他逻辑不会做过多描述

以下调试的参数为

-da -dsa -Xint -XX:+UseSerialGC com.hx.test02.Test02WeakReferenceAfterGc

以下调试的基于 openjdk9, 并且有一部分个人方便调试的调整, 调整的部分为

jvm.cpp

JVM_ENTRY_NO_ENV(void, JVM_GC(void))JVMWrapper("JVM_GC");if (!DisableExplicitGC) {
-    Universe::heap()->collect(GCCause::_java_lang_system_gc);
+    VM_GenCollectForAllocation op(100, true, Universe::heap()->total_collections());
+    VMThread::execute(&op);}
JVM_END

System.gc 调整成为 ygc, 所以 可能和我们直接使用 jdk 运行的运行时情况稍有不一致的地方, 所以本文的调试 可能会存在一些局限

另外 由于本人水平有限, 理解能力有限有限, 可能也会导致一些问题的存在

问题的细节

1. 相关代码片段

首先先贴一下一部分关键代码, 在gc处理的过程中 会进行引用处理, 这里的 _discoveredXXRefs 来自于 复制算法遍历活跃对象的时候额外的针对 Reference 对象做了一些 Discover[参见instanceRefKlass.inline.oop_oop_iterate]

ReferenceProcessor::process_discovered_references

ReferenceProcessorStats ReferenceProcessor::process_discovered_references(BoolObjectClosure*           is_alive,OopClosure*                  keep_alive,VoidClosure*                 complete_gc,AbstractRefProcTaskExecutor* task_executor,GCTimer*                     gc_timer) {assert(!enqueuing_is_done(), "If here enqueuing should not be complete");// Stop treating discovered references specially.disable_discovery();// If discovery was concurrent, someone could have modified// the value of the static field in the j.l.r.SoftReference// class that holds the soft reference timestamp clock using// reflection or Unsafe between when discovery was enabled and// now. Unconditionally update the static field in ReferenceProcessor// here so that we use the new value during processing of the// discovered soft refs._soft_ref_timestamp_clock = java_lang_ref_SoftReference::clock();ReferenceProcessorStats stats(total_count(_discoveredSoftRefs),total_count(_discoveredWeakRefs),total_count(_discoveredFinalRefs),total_count(_discoveredPhantomRefs));// Soft references{GCTraceTime(Debug, gc, ref) tt("SoftReference", gc_timer);process_discovered_reflist(_discoveredSoftRefs, _current_soft_ref_policy, true,is_alive, keep_alive, complete_gc, task_executor);}update_soft_ref_master_clock();// Weak references{GCTraceTime(Debug, gc, ref) tt("WeakReference", gc_timer);process_discovered_reflist(_discoveredWeakRefs, NULL, true,is_alive, keep_alive, complete_gc, task_executor);}// Final references{GCTraceTime(Debug, gc, ref) tt("FinalReference", gc_timer);process_discovered_reflist(_discoveredFinalRefs, NULL, false,is_alive, keep_alive, complete_gc, task_executor);}// Phantom references{GCTraceTime(Debug, gc, ref) tt("PhantomReference", gc_timer);process_discovered_reflist(_discoveredPhantomRefs, NULL, true,is_alive, keep_alive, complete_gc, task_executor);}// Weak global JNI references. It would make more sense (semantically) to// traverse these simultaneously with the regular weak references above, but// that is not how the JDK1.2 specification is. See #4126360. Native code can// thus use JNI weak references to circumvent the phantom references and// resurrect a "post-mortem" object.{GCTraceTime(Debug, gc, ref) tt("JNI Weak Reference", gc_timer);if (task_executor != NULL) {task_executor->set_single_threaded_mode();}process_phaseJNI(is_alive, keep_alive, complete_gc);}log_debug(gc, ref)("Ref Counts: Soft: " SIZE_FORMAT " Weak: " SIZE_FORMAT " Final: " SIZE_FORMAT " Phantom: " SIZE_FORMAT,stats.soft_count(), stats.weak_count(), stats.final_count(), stats.phantom_count());log_develop_trace(gc, ref)("JNI Weak Reference count: " SIZE_FORMAT, count_jni_refs());return stats;
}

ReferenceProcessor::process_discovered_reflist

void ReferenceProcessor::process_discovered_reflist(DiscoveredList               refs_lists[],ReferencePolicy*             policy,bool                         clear_referent,BoolObjectClosure*           is_alive,OopClosure*                  keep_alive,VoidClosure*                 complete_gc,AbstractRefProcTaskExecutor* task_executor)
{bool mt_processing = task_executor != NULL && _processing_is_mt;// If discovery used MT and a dynamic number of GC threads, then// the queues must be balanced for correctness if fewer than the// maximum number of queues were used.  The number of queue used// during discovery may be different than the number to be used// for processing so don't depend of _num_q < _max_num_q as part// of the test.bool must_balance = _discovery_is_mt;if ((mt_processing && ParallelRefProcBalancingEnabled) ||must_balance) {balance_queues(refs_lists);}// Phase 1 (soft refs only):// . Traverse the list and remove any SoftReferences whose//   referents are not alive, but that should be kept alive for//   policy reasons. Keep alive the transitive closure of all//   such referents.if (policy != NULL) {if (mt_processing) {RefProcPhase1Task phase1(*this, refs_lists, policy, true /*marks_oops_alive*/);task_executor->execute(phase1);} else {for (uint i = 0; i < _max_num_q; i++) {process_phase1(refs_lists[i], policy,is_alive, keep_alive, complete_gc);}}} else { // policy == NULLassert(refs_lists != _discoveredSoftRefs,"Policy must be specified for soft references.");}// Phase 2:// . Traverse the list and remove any refs whose referents are alive.if (mt_processing) {RefProcPhase2Task phase2(*this, refs_lists, !discovery_is_atomic() /*marks_oops_alive*/);task_executor->execute(phase2);} else {for (uint i = 0; i < _max_num_q; i++) {process_phase2(refs_lists[i], is_alive, keep_alive, complete_gc);}}// Phase 3:// . Traverse the list and process referents as appropriate.if (mt_processing) {RefProcPhase3Task phase3(*this, refs_lists, clear_referent, true /*marks_oops_alive*/);task_executor->execute(phase3);} else {for (uint i = 0; i < _max_num_q; i++) {process_phase3(refs_lists[i], clear_referent,is_alive, keep_alive, complete_gc);}}
}

process_phase1 : 主要是 SoftReference 的处理[只有SoftReference传入了 policy], 根据 referencePolicy 来校验当前 Reference 是否应该移出 discoverList

process_phase2 : 如果 referent 经过了 ygc 还存活着, 那么 将当前 Reference 移出 discoverList

process_phase3 : 如果需要 clear_referent, 则清理掉 Reference.referent, 否则 将Reference.referent移动到 存活对象区域 [仅仅FinalReference传入为false, FinalReference业务处理的时候还需要referent]

ReferenceProcessor::process_phase3

// Traverse the list and process the referents, by either
// clearing them or keeping them (and their reachable
// closure) alive.
void
ReferenceProcessor::process_phase3(DiscoveredList&    refs_list,bool               clear_referent,BoolObjectClosure* is_alive,OopClosure*        keep_alive,VoidClosure*       complete_gc) {ResourceMark rm;DiscoveredListIterator iter(refs_list, keep_alive, is_alive);while (iter.has_next()) {iter.load_ptrs(DEBUG_ONLY(false /* allow_null_referent */));if (clear_referent) {// NULL out referent pointeriter.clear_referent();} else {// keep the referent arounditer.make_referent_alive();}log_develop_trace(gc, ref)("Adding %sreference (" INTPTR_FORMAT ": %s) as pending",clear_referent ? "cleared " : "", p2i(iter.obj()), iter.obj()->klass()->internal_name());assert(iter.obj()->is_oop(UseConcMarkSweepGC), "Adding a bad reference");iter.next();}// Close the reachable setcomplete_gc->do_void();
}

经过 ReferenceProcessor::process_discovered_references 处理之后, 最后 还存在于 discoverList 的 Reference 与 Reference.pending 关联 [gc处理之后, genCollectedHeap.collect_generation里面 rp->enqueue_discovered_references]

然后 ReferenceHandler 线程会进行下一个阶段的处理, 将 Reference.pending 关联的列表的 所有的 Reference 关联到 Reference 对应的队列[参见 Reference$ReferenceHandler]

2. Test02WeakReferenceAfterGc$Obj 没有重写 finalize

首先我们来看一下 Test02WeakReferenceAfterGc$Obj 没有重写 finalize 方法的场景

三个断点, thread.create_vm 方法末尾一个, defNewGeneration.collect 里面 ref_processor.process_discovered_references 一个, referenceProcessor.process_discovered_references 里面 process_discovered_reflist(_discoveredPhantomRefs 一个

当断点停留在 "referenceProcessor.process_discovered_references" 里面的时候

2.1 确定当前位置

找到 main 线程, 打印 main 线程的 stackTrace, 从这里 可以知道 目前是 在 第一个 System.gc 方法的执行期间

$jerry : thread->print()
"main" #1 prio=5 os_prio=31 tid=0x00007fa786803800 nid=0x2403 waiting on condition [0x0000700007756000]java.lang.Thread.State: RUNNABLEJavaThread state: _thread_blocked
Thread: 0x00007fa786803800  [0x2403] State: _at_safepoint _has_called_back 0 _at_poll_safepoint 0$jerry : thread->print_stack()JavaThread state: _thread_blockedat java.lang.Runtime.gc(java.base/Native Method)at java.lang.System.gc(java.base/System.java:1726)at com.hx.test02.Test02WeakReferenceAfterGc.main(Test02WeakReferenceAfterGc.java:27)

2.2 process_discovered_reflist(_discoveredPhantomRefs 处理之前

然后我们回到 gc 线程, 在断点处 执行如下脚本, 打印探测到的 PhantomReference 列表

oop current = ((_discoveredPhantomRefs)->head());
for(int i=0; i<_discoveredPhantomRefs->length(); i++) {// tty->print_cr(current->klass()->external_name());current.print();current = java_lang_ref_Reference::discovered(current);
}

得到结果如下

jdk.internal.ref.CleanerImpl$PhantomCleanableRef
{0x000000074275dcd0} - klass: 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'- ---- fields (total size 6 words):- private strict 'referent' 'Ljava/lang/Object;' @12  a 'java/lang/invoke/ConstantCallSite'{0x00000007404034b0} (e8080696 e84d06ce)- volatile strict 'queue' 'Ljava/lang/ref/ReferenceQueue;' @16  a 'java/lang/ref/ReferenceQueue'{0x0000000742683670} (e84d06ce 0)- volatile 'next' 'Ljava/lang/ref/Reference;' @20  NULL (0 e84ebb91)- private transient strict 'discovered' 'Ljava/lang/ref/Reference;' @24  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x000000074275dc88} (e84ebb91 e84eaf9e)- strict 'prev' 'Ljdk/internal/ref/PhantomCleanable;' @28  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x0000000742757cf0} (e84eaf9e e84ebb91)- strict 'next' 'Ljdk/internal/ref/PhantomCleanable;' @32  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x000000074275dc88} (e84ebb91 e84d2fe6)- private final strict 'list' 'Ljdk/internal/ref/PhantomCleanable;' @36  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x0000000742697f30} (e84d2fe6 e84ec6c6)- private final 'action' 'Ljava/lang/Runnable;' @40  a 'java/lang/invoke/MethodHandleNatives$CallSiteContext'{0x0000000742763630} (e84ec6c6 0)
jdk.internal.ref.CleanerImpl$PhantomCleanableRef
{0x000000074275dc88} - klass: 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'- ---- fields (total size 6 words):- private strict 'referent' 'Ljava/lang/Object;' @12  a 'java/lang/invoke/ConstantCallSite'{0x000000074036f6a0} (e806ded4 e84d06ce)- volatile strict 'queue' 'Ljava/lang/ref/ReferenceQueue;' @16  a 'java/lang/ref/ReferenceQueue'{0x0000000742683670} (e84d06ce 0)- volatile 'next' 'Ljava/lang/ref/Reference;' @20  NULL (0 e84eaf9e)- private transient strict 'discovered' 'Ljava/lang/ref/Reference;' @24  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x0000000742757cf0} (e84eaf9e e84ebb9a)- strict 'prev' 'Ljdk/internal/ref/PhantomCleanable;' @28  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x000000074275dcd0} (e84ebb9a e84eaf95)- strict 'next' 'Ljdk/internal/ref/PhantomCleanable;' @32  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x0000000742757ca8} (e84eaf95 e84d2fe6)- private final strict 'list' 'Ljdk/internal/ref/PhantomCleanable;' @36  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x0000000742697f30} (e84d2fe6 e84ec6c3)- private final 'action' 'Ljava/lang/Runnable;' @40  a 'java/lang/invoke/MethodHandleNatives$CallSiteContext'{0x0000000742763618} (e84ec6c3 0)
jdk.internal.ref.CleanerImpl$PhantomCleanableRef
{0x0000000742757cf0} - klass: 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'- ---- fields (total size 6 words):- private strict 'referent' 'Ljava/lang/Object;' @12  a 'java/lang/invoke/ConstantCallSite'{0x0000000740409798} (e80812f3 e84d06ce)- volatile strict 'queue' 'Ljava/lang/ref/ReferenceQueue;' @16  a 'java/lang/ref/ReferenceQueue'{0x0000000742683670} (e84d06ce 0)- volatile 'next' 'Ljava/lang/ref/Reference;' @20  NULL (0 e84eaf95)- private transient strict 'discovered' 'Ljava/lang/ref/Reference;' @24  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x0000000742757ca8} (e84eaf95 e84ea6b5)- strict 'prev' 'Ljdk/internal/ref/PhantomCleanable;' @28  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x00000007427535a8} (e84ea6b5 e84ebb9a)- strict 'next' 'Ljdk/internal/ref/PhantomCleanable;' @32  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x000000074275dcd0} (e84ebb9a e84d2fe6)- private final strict 'list' 'Ljdk/internal/ref/PhantomCleanable;' @36  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x0000000742697f30} (e84d2fe6 e84ebba0)- private final 'action' 'Ljava/lang/Runnable;' @40  a 'java/lang/invoke/MethodHandleNatives$CallSiteContext'{0x000000074275dd00} (e84ebba0 0)
jdk.internal.ref.CleanerImpl$PhantomCleanableRef
{0x0000000742757ca8} - klass: 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'- ---- fields (total size 6 words):- private strict 'referent' 'Ljava/lang/Object;' @12  a 'java/lang/invoke/ConstantCallSite'{0x000000074036d7f8} (e806daff e84d06ce)- volatile strict 'queue' 'Ljava/lang/ref/ReferenceQueue;' @16  a 'java/lang/ref/ReferenceQueue'{0x0000000742683670} (e84d06ce 0)- volatile 'next' 'Ljava/lang/ref/Reference;' @20  NULL (0 e84ea6b5)- private transient strict 'discovered' 'Ljava/lang/ref/Reference;' @24  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x00000007427535a8} (e84ea6b5 e84ebb91)- strict 'prev' 'Ljdk/internal/ref/PhantomCleanable;' @28  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x000000074275dc88} (e84ebb91 e84ea6ac)- strict 'next' 'Ljdk/internal/ref/PhantomCleanable;' @32  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x0000000742753560} (e84ea6ac e84d2fe6)- private final strict 'list' 'Ljdk/internal/ref/PhantomCleanable;' @36  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x0000000742697f30} (e84d2fe6 e84ebb97)- private final 'action' 'Ljava/lang/Runnable;' @40  a 'java/lang/invoke/MethodHandleNatives$CallSiteContext'{0x000000074275dcb8} (e84ebb97 0)
jdk.internal.ref.CleanerImpl$PhantomCleanableRef
{0x00000007427535a8} - klass: 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'- ---- fields (total size 6 words):- private strict 'referent' 'Ljava/lang/Object;' @12  a 'java/lang/invoke/ConstantCallSite'{0x0000000740410730} (e80820e6 e84d06ce)- volatile strict 'queue' 'Ljava/lang/ref/ReferenceQueue;' @16  a 'java/lang/ref/ReferenceQueue'{0x0000000742683670} (e84d06ce 0)- volatile 'next' 'Ljava/lang/ref/Reference;' @20  NULL (0 e84ea6ac)- private transient strict 'discovered' 'Ljava/lang/ref/Reference;' @24  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x0000000742753560} (e84ea6ac e84e9c27)- strict 'prev' 'Ljdk/internal/ref/PhantomCleanable;' @28  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x000000074274e138} (e84e9c27 e84eaf9e)- strict 'next' 'Ljdk/internal/ref/PhantomCleanable;' @32  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x0000000742757cf0} (e84eaf9e e84d2fe6)- private final strict 'list' 'Ljdk/internal/ref/PhantomCleanable;' @36  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x0000000742697f30} (e84d2fe6 e84eafa4)- private final 'action' 'Ljava/lang/Runnable;' @40  a 'java/lang/invoke/MethodHandleNatives$CallSiteContext'{0x0000000742757d20} (e84eafa4 0)
jdk.internal.ref.CleanerImpl$PhantomCleanableRef
{0x0000000742753560} - klass: 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'- ---- fields (total size 6 words):- private strict 'referent' 'Ljava/lang/Object;' @12  a 'java/lang/invoke/ConstantCallSite'{0x000000074036a828} (e806d505 e84d06ce)- volatile strict 'queue' 'Ljava/lang/ref/ReferenceQueue;' @16  a 'java/lang/ref/ReferenceQueue'{0x0000000742683670} (e84d06ce 0)- volatile 'next' 'Ljava/lang/ref/Reference;' @20  NULL (0 e84e9c27)- private transient strict 'discovered' 'Ljava/lang/ref/Reference;' @24  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x000000074274e138} (e84e9c27 e84eaf95)- strict 'prev' 'Ljdk/internal/ref/PhantomCleanable;' @28  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x0000000742757ca8} (e84eaf95 e84e9c1e)- strict 'next' 'Ljdk/internal/ref/PhantomCleanable;' @32  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x000000074274e0f0} (e84e9c1e e84d2fe6)- private final strict 'list' 'Ljdk/internal/ref/PhantomCleanable;' @36  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x0000000742697f30} (e84d2fe6 e84eaf9b)- private final 'action' 'Ljava/lang/Runnable;' @40  a 'java/lang/invoke/MethodHandleNatives$CallSiteContext'{0x0000000742757cd8} (e84eaf9b 0)
jdk.internal.ref.CleanerImpl$PhantomCleanableRef
{0x000000074274e138} - klass: 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'- ---- fields (total size 6 words):- private strict 'referent' 'Ljava/lang/Object;' @12  a 'java/lang/invoke/ConstantCallSite'{0x00000007404242d0} (e808485a e84d06ce)- volatile strict 'queue' 'Ljava/lang/ref/ReferenceQueue;' @16  a 'java/lang/ref/ReferenceQueue'{0x0000000742683670} (e84d06ce 0)- volatile 'next' 'Ljava/lang/ref/Reference;' @20  NULL (0 e84e9c1e)- private transient strict 'discovered' 'Ljava/lang/ref/Reference;' @24  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x000000074274e0f0} (e84e9c1e e84e8c52)- strict 'prev' 'Ljdk/internal/ref/PhantomCleanable;' @28  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x0000000742746290} (e84e8c52 e84ea6b5)- strict 'next' 'Ljdk/internal/ref/PhantomCleanable;' @32  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x00000007427535a8} (e84ea6b5 e84d2fe6)- private final strict 'list' 'Ljdk/internal/ref/PhantomCleanable;' @36  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x0000000742697f30} (e84d2fe6 e84ea6bb)- private final 'action' 'Ljava/lang/Runnable;' @40  a 'java/lang/invoke/MethodHandleNatives$CallSiteContext'{0x00000007427535d8} (e84ea6bb 0)
jdk.internal.ref.CleanerImpl$PhantomCleanableRef
{0x000000074274e0f0} - klass: 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'- ---- fields (total size 6 words):- private strict 'referent' 'Ljava/lang/Object;' @12  a 'java/lang/invoke/ConstantCallSite'{0x0000000740359488} (e806b291 e84d06ce)- volatile strict 'queue' 'Ljava/lang/ref/ReferenceQueue;' @16  a 'java/lang/ref/ReferenceQueue'{0x0000000742683670} (e84d06ce 0)- volatile 'next' 'Ljava/lang/ref/Reference;' @20  NULL (0 e84e8c52)- private transient strict 'discovered' 'Ljava/lang/ref/Reference;' @24  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x0000000742746290} (e84e8c52 e84ea6ac)- strict 'prev' 'Ljdk/internal/ref/PhantomCleanable;' @28  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x0000000742753560} (e84ea6ac e84e8c49)- strict 'next' 'Ljdk/internal/ref/PhantomCleanable;' @32  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x0000000742746248} (e84e8c49 e84d2fe6)- private final strict 'list' 'Ljdk/internal/ref/PhantomCleanable;' @36  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x0000000742697f30} (e84d2fe6 e84ea6b2)- private final 'action' 'Ljava/lang/Runnable;' @40  a 'java/lang/invoke/MethodHandleNatives$CallSiteContext'{0x0000000742753590} (e84ea6b2 0)
jdk.internal.ref.CleanerImpl$PhantomCleanableRef
{0x0000000742746290} - klass: 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'- ---- fields (total size 6 words):- private strict 'referent' 'Ljava/lang/Object;' @12  a 'java/lang/invoke/ConstantCallSite'{0x0000000740431a28} (e8086345 e84d06ce)- volatile strict 'queue' 'Ljava/lang/ref/ReferenceQueue;' @16  a 'java/lang/ref/ReferenceQueue'{0x0000000742683670} (e84d06ce 0)- volatile 'next' 'Ljava/lang/ref/Reference;' @20  NULL (0 e84e8c49)- private transient strict 'discovered' 'Ljava/lang/ref/Reference;' @24  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x0000000742746248} (e84e8c49 e84e77b7)- strict 'prev' 'Ljdk/internal/ref/PhantomCleanable;' @28  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x000000074273bdb8} (e84e77b7 e84e9c27)- strict 'next' 'Ljdk/internal/ref/PhantomCleanable;' @32  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x000000074274e138} (e84e9c27 e84d2fe6)- private final strict 'list' 'Ljdk/internal/ref/PhantomCleanable;' @36  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x0000000742697f30} (e84d2fe6 e84e9c2d)- private final 'action' 'Ljava/lang/Runnable;' @40  a 'java/lang/invoke/MethodHandleNatives$CallSiteContext'{0x000000074274e168} (e84e9c2d 0)
jdk.internal.ref.CleanerImpl$PhantomCleanableRef
{0x0000000742746248} - klass: 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'- ---- fields (total size 6 words):- private strict 'referent' 'Ljava/lang/Object;' @12  a 'java/lang/invoke/ConstantCallSite'{0x0000000740351e60} (e806a3cc e84d06ce)- volatile strict 'queue' 'Ljava/lang/ref/ReferenceQueue;' @16  a 'java/lang/ref/ReferenceQueue'{0x0000000742683670} (e84d06ce 0)- volatile 'next' 'Ljava/lang/ref/Reference;' @20  NULL (0 e84e77b7)- private transient strict 'discovered' 'Ljava/lang/ref/Reference;' @24  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x000000074273bdb8} (e84e77b7 e84e9c1e)- strict 'prev' 'Ljdk/internal/ref/PhantomCleanable;' @28  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x000000074274e0f0} (e84e9c1e e84e77ae)- strict 'next' 'Ljdk/internal/ref/PhantomCleanable;' @32  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x000000074273bd70} (e84e77ae e84d2fe6)- private final strict 'list' 'Ljdk/internal/ref/PhantomCleanable;' @36  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x0000000742697f30} (e84d2fe6 e84e9c24)- private final 'action' 'Ljava/lang/Runnable;' @40  a 'java/lang/invoke/MethodHandleNatives$CallSiteContext'{0x000000074274e120} (e84e9c24 0)
jdk.internal.ref.CleanerImpl$PhantomCleanableRef
{0x000000074273bdb8} - klass: 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'- ---- fields (total size 6 words):- private strict 'referent' 'Ljava/lang/Object;' @12  a 'java/lang/invoke/ConstantCallSite'{0x0000000740438e00} (e80871c0 e84d06ce)- volatile strict 'queue' 'Ljava/lang/ref/ReferenceQueue;' @16  a 'java/lang/ref/ReferenceQueue'{0x0000000742683670} (e84d06ce 0)- volatile 'next' 'Ljava/lang/ref/Reference;' @20  NULL (0 e84e77ae)- private transient strict 'discovered' 'Ljava/lang/ref/Reference;' @24  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x000000074273bd70} (e84e77ae e84e571d)- strict 'prev' 'Ljdk/internal/ref/PhantomCleanable;' @28  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x000000074272b8e8} (e84e571d e84e8c52)- strict 'next' 'Ljdk/internal/ref/PhantomCleanable;' @32  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x0000000742746290} (e84e8c52 e84d2fe6)- private final strict 'list' 'Ljdk/internal/ref/PhantomCleanable;' @36  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x0000000742697f30} (e84d2fe6 e84e8c58)- private final 'action' 'Ljava/lang/Runnable;' @40  a 'java/lang/invoke/MethodHandleNatives$CallSiteContext'{0x00000007427462c0} (e84e8c58 0)
jdk.internal.ref.CleanerImpl$PhantomCleanableRef
{0x000000074273bd70} - klass: 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'- ---- fields (total size 6 words):- private strict 'referent' 'Ljava/lang/Object;' @12  a 'java/lang/invoke/ConstantCallSite'{0x000000074019cef8} (e80339df e84d06ce)- volatile strict 'queue' 'Ljava/lang/ref/ReferenceQueue;' @16  a 'java/lang/ref/ReferenceQueue'{0x0000000742683670} (e84d06ce 0)- volatile 'next' 'Ljava/lang/ref/Reference;' @20  NULL (0 e84e571d)- private transient strict 'discovered' 'Ljava/lang/ref/Reference;' @24  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x000000074272b8e8} (e84e571d e84e8c49)- strict 'prev' 'Ljdk/internal/ref/PhantomCleanable;' @28  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x0000000742746248} (e84e8c49 e84e5714)- strict 'next' 'Ljdk/internal/ref/PhantomCleanable;' @32  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x000000074272b8a0} (e84e5714 e84d2fe6)- private final strict 'list' 'Ljdk/internal/ref/PhantomCleanable;' @36  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x0000000742697f30} (e84d2fe6 e84e8c4f)- private final 'action' 'Ljava/lang/Runnable;' @40  a 'java/lang/invoke/MethodHandleNatives$CallSiteContext'{0x0000000742746278} (e84e8c4f 0)
jdk.internal.ref.CleanerImpl$PhantomCleanableRef
{0x000000074272b8e8} - klass: 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'- ---- fields (total size 6 words):- private strict 'referent' 'Ljava/lang/Object;' @12  a 'java/lang/invoke/ConstantCallSite'{0x0000000740445580} (e8088ab0 e84d06ce)- volatile strict 'queue' 'Ljava/lang/ref/ReferenceQueue;' @16  a 'java/lang/ref/ReferenceQueue'{0x0000000742683670} (e84d06ce 0)- volatile 'next' 'Ljava/lang/ref/Reference;' @20  NULL (0 e84e5714)- private transient strict 'discovered' 'Ljava/lang/ref/Reference;' @24  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x000000074272b8a0} (e84e5714 e84e2db8)- strict 'prev' 'Ljdk/internal/ref/PhantomCleanable;' @28  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x0000000742716dc0} (e84e2db8 e84e77b7)- strict 'next' 'Ljdk/internal/ref/PhantomCleanable;' @32  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x000000074273bdb8} (e84e77b7 e84d2fe6)- private final strict 'list' 'Ljdk/internal/ref/PhantomCleanable;' @36  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x0000000742697f30} (e84d2fe6 e84e77bd)- private final 'action' 'Ljava/lang/Runnable;' @40  a 'java/lang/invoke/MethodHandleNatives$CallSiteContext'{0x000000074273bde8} (e84e77bd 0)
jdk.internal.ref.CleanerImpl$PhantomCleanableRef
{0x000000074272b8a0} - klass: 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'- ---- fields (total size 6 words):- private strict 'referent' 'Ljava/lang/Object;' @12  a 'java/lang/invoke/ConstantCallSite'{0x0000000740193d48} (e80327a9 e84d06ce)- volatile strict 'queue' 'Ljava/lang/ref/ReferenceQueue;' @16  a 'java/lang/ref/ReferenceQueue'{0x0000000742683670} (e84d06ce 0)- volatile 'next' 'Ljava/lang/ref/Reference;' @20  NULL (0 e84e2db8)- private transient strict 'discovered' 'Ljava/lang/ref/Reference;' @24  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x0000000742716dc0} (e84e2db8 e84e77ae)- strict 'prev' 'Ljdk/internal/ref/PhantomCleanable;' @28  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x000000074273bd70} (e84e77ae e84e2daf)- strict 'next' 'Ljdk/internal/ref/PhantomCleanable;' @32  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x0000000742716d78} (e84e2daf e84d2fe6)- private final strict 'list' 'Ljdk/internal/ref/PhantomCleanable;' @36  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x0000000742697f30} (e84d2fe6 e84e77b4)- private final 'action' 'Ljava/lang/Runnable;' @40  a 'java/lang/invoke/MethodHandleNatives$CallSiteContext'{0x000000074273bda0} (e84e77b4 0)
jdk.internal.ref.CleanerImpl$PhantomCleanableRef
{0x0000000742716dc0} - klass: 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'- ---- fields (total size 6 words):- private strict 'referent' 'Ljava/lang/Object;' @12  a 'java/lang/invoke/ConstantCallSite'{0x0000000740449470} (e808928e e84d06ce)- volatile strict 'queue' 'Ljava/lang/ref/ReferenceQueue;' @16  a 'java/lang/ref/ReferenceQueue'{0x0000000742683670} (e84d06ce 0)- volatile 'next' 'Ljava/lang/ref/Reference;' @20  NULL (0 e84e2daf)- private transient strict 'discovered' 'Ljava/lang/ref/Reference;' @24  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x0000000742716d78} (e84e2daf e84de643)- strict 'prev' 'Ljdk/internal/ref/PhantomCleanable;' @28  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x00000007426f3218} (e84de643 e84e571d)- strict 'next' 'Ljdk/internal/ref/PhantomCleanable;' @32  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x000000074272b8e8} (e84e571d e84d2fe6)- private final strict 'list' 'Ljdk/internal/ref/PhantomCleanable;' @36  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x0000000742697f30} (e84d2fe6 e84e5723)- private final 'action' 'Ljava/lang/Runnable;' @40  a 'java/lang/invoke/MethodHandleNatives$CallSiteContext'{0x000000074272b918} (e84e5723 0)
jdk.internal.ref.CleanerImpl$PhantomCleanableRef
{0x0000000742716d78} - klass: 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'- ---- fields (total size 6 words):- private strict 'referent' 'Ljava/lang/Object;' @12  a 'java/lang/invoke/ConstantCallSite'{0x0000000740188140} (e8031028 e84d06ce)- volatile strict 'queue' 'Ljava/lang/ref/ReferenceQueue;' @16  a 'java/lang/ref/ReferenceQueue'{0x0000000742683670} (e84d06ce 0)- volatile 'next' 'Ljava/lang/ref/Reference;' @20  NULL (0 e84de643)- private transient strict 'discovered' 'Ljava/lang/ref/Reference;' @24  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x00000007426f3218} (e84de643 e84e5714)- strict 'prev' 'Ljdk/internal/ref/PhantomCleanable;' @28  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x000000074272b8a0} (e84e5714 e84de63a)- strict 'next' 'Ljdk/internal/ref/PhantomCleanable;' @32  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x00000007426f31d0} (e84de63a e84d2fe6)- private final strict 'list' 'Ljdk/internal/ref/PhantomCleanable;' @36  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x0000000742697f30} (e84d2fe6 e84e571a)- private final 'action' 'Ljava/lang/Runnable;' @40  a 'java/lang/invoke/MethodHandleNatives$CallSiteContext'{0x000000074272b8d0} (e84e571a 0)
jdk.internal.ref.CleanerImpl$PhantomCleanableRef
{0x00000007426f3218} - klass: 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'- ---- fields (total size 6 words):- private strict 'referent' 'Ljava/lang/Object;' @12  a 'java/lang/invoke/ConstantCallSite'{0x000000074044c550} (e80898aa e84d06ce)- volatile strict 'queue' 'Ljava/lang/ref/ReferenceQueue;' @16  a 'java/lang/ref/ReferenceQueue'{0x0000000742683670} (e84d06ce 0)- volatile 'next' 'Ljava/lang/ref/Reference;' @20  NULL (0 e84de63a)- private transient strict 'discovered' 'Ljava/lang/ref/Reference;' @24  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x00000007426f31d0} (e84de63a e84da7f7)- strict 'prev' 'Ljdk/internal/ref/PhantomCleanable;' @28  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x00000007426d3fb8} (e84da7f7 e84e2db8)- strict 'next' 'Ljdk/internal/ref/PhantomCleanable;' @32  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x0000000742716dc0} (e84e2db8 e84d2fe6)- private final strict 'list' 'Ljdk/internal/ref/PhantomCleanable;' @36  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x0000000742697f30} (e84d2fe6 e84e2dbe)- private final 'action' 'Ljava/lang/Runnable;' @40  a 'java/lang/invoke/MethodHandleNatives$CallSiteContext'{0x0000000742716df0} (e84e2dbe 0)
jdk.internal.ref.CleanerImpl$PhantomCleanableRef
{0x00000007426f31d0} - klass: 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'- ---- fields (total size 6 words):- private strict 'referent' 'Ljava/lang/Object;' @12  a 'java/lang/invoke/ConstantCallSite'{0x0000000740172188} (e802e431 e84d06ce)- volatile strict 'queue' 'Ljava/lang/ref/ReferenceQueue;' @16  a 'java/lang/ref/ReferenceQueue'{0x0000000742683670} (e84d06ce 0)- volatile 'next' 'Ljava/lang/ref/Reference;' @20  NULL (0 e84da7f7)- private transient strict 'discovered' 'Ljava/lang/ref/Reference;' @24  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x00000007426d3fb8} (e84da7f7 e84e2daf)- strict 'prev' 'Ljdk/internal/ref/PhantomCleanable;' @28  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x0000000742716d78} (e84e2daf e84da7f1)- strict 'next' 'Ljdk/internal/ref/PhantomCleanable;' @32  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x00000007426d3f88} (e84da7f1 e84d2fe6)- private final strict 'list' 'Ljdk/internal/ref/PhantomCleanable;' @36  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x0000000742697f30} (e84d2fe6 e84e2db5)- private final 'action' 'Ljava/lang/Runnable;' @40  a 'java/lang/invoke/MethodHandleNatives$CallSiteContext'{0x0000000742716da8} (e84e2db5 0)
jdk.internal.ref.CleanerImpl$PhantomCleanableRef
{0x00000007426d3fb8} - klass: 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'- ---- fields (total size 6 words):- private strict 'referent' 'Ljava/lang/Object;' @12  a 'java/lang/invoke/ConstantCallSite'{0x000000074044ed28} (e8089da5 e84d06ce)- volatile strict 'queue' 'Ljava/lang/ref/ReferenceQueue;' @16  a 'java/lang/ref/ReferenceQueue'{0x0000000742683670} (e84d06ce 0)- volatile 'next' 'Ljava/lang/ref/Reference;' @20  NULL (0 e84da7f1)- private transient strict 'discovered' 'Ljava/lang/ref/Reference;' @24  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x00000007426d3f88} (e84da7f1 e84d6a6d)- strict 'prev' 'Ljdk/internal/ref/PhantomCleanable;' @28  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x00000007426b5368} (e84d6a6d e84de643)- strict 'next' 'Ljdk/internal/ref/PhantomCleanable;' @32  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x00000007426f3218} (e84de643 e84d2fe6)- private final strict 'list' 'Ljdk/internal/ref/PhantomCleanable;' @36  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x0000000742697f30} (e84d2fe6 e84de649)- private final 'action' 'Ljava/lang/Runnable;' @40  a 'java/lang/invoke/MethodHandleNatives$CallSiteContext'{0x00000007426f3248} (e84de649 0)
jdk.internal.ref.CleanerImpl$PhantomCleanableRef
{0x00000007426d3f88} - klass: 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'- ---- fields (total size 6 words):- private strict 'referent' 'Ljava/lang/Object;' @12  a 'sun/nio/fs/NativeBuffer'{0x0000000740036f20} (e8006de4 e84d06ce)- volatile strict 'queue' 'Ljava/lang/ref/ReferenceQueue;' @16  a 'java/lang/ref/ReferenceQueue'{0x0000000742683670} (e84d06ce 0)- volatile 'next' 'Ljava/lang/ref/Reference;' @20  NULL (0 e84d6a6d)- private transient strict 'discovered' 'Ljava/lang/ref/Reference;' @24  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x00000007426b5368} (e84d6a6d e84de63a)- strict 'prev' 'Ljdk/internal/ref/PhantomCleanable;' @28  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x00000007426f31d0} (e84de63a e84d6a68)- strict 'next' 'Ljdk/internal/ref/PhantomCleanable;' @32  a 'jdk/internal/ref/CleanerImpl$CleanerCleanable'{0x00000007426b5340} (e84d6a68 e84d2fe6)- private final strict 'list' 'Ljdk/internal/ref/PhantomCleanable;' @36  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x0000000742697f30} (e84d2fe6 e84de640)- private final 'action' 'Ljava/lang/Runnable;' @40  a 'sun/nio/fs/NativeBuffer$Deallocator'{0x00000007426f3200} (e84de640 0)
jdk.internal.ref.CleanerImpl$PhantomCleanableRef
{0x00000007426b5368} - klass: 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'- ---- fields (total size 6 words):- private strict 'referent' 'Ljava/lang/Object;' @12  a 'java/lang/invoke/ConstantCallSite'{0x000000074045dfe8} (e808bbfd e84d06ce)- volatile strict 'queue' 'Ljava/lang/ref/ReferenceQueue;' @16  a 'java/lang/ref/ReferenceQueue'{0x0000000742683670} (e84d06ce 0)- volatile 'next' 'Ljava/lang/ref/Reference;' @20  NULL (0 e84d2df2)- private transient strict 'discovered' 'Ljava/lang/ref/Reference;' @24  a 'jdk/internal/ref/Cleaner'{0x0000000742696f90} (e84d2df2 e84d2fe6)- strict 'prev' 'Ljdk/internal/ref/PhantomCleanable;' @28  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x0000000742697f30} (e84d2fe6 e84da7f7)- strict 'next' 'Ljdk/internal/ref/PhantomCleanable;' @32  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x00000007426d3fb8} (e84da7f7 e84d2fe6)- private final strict 'list' 'Ljdk/internal/ref/PhantomCleanable;' @36  a 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'{0x0000000742697f30} (e84d2fe6 e84da7fd)- private final 'action' 'Ljava/lang/Runnable;' @40  a 'java/lang/invoke/MethodHandleNatives$CallSiteContext'{0x00000007426d3fe8} (e84da7fd 0)
jdk.internal.ref.Cleaner
{0x0000000742696f90} - klass: 'jdk/internal/ref/Cleaner'- ---- fields (total size 5 words):- private strict 'referent' 'Ljava/lang/Object;' @12  a 'java/nio/DirectByteBuffer'{0x0000000740189c90} (e8031392 e84d2dee)- volatile strict 'queue' 'Ljava/lang/ref/ReferenceQueue;' @16  a 'java/lang/ref/ReferenceQueue'{0x0000000742696f70} (e84d2dee 0)- volatile 'next' 'Ljava/lang/ref/Reference;' @20  NULL (0 e84d0774)- private transient strict 'discovered' 'Ljava/lang/ref/Reference;' @24  a 'java/lang/ref/PhantomReference'{0x0000000742683ba0} (e84d0774 0)- private 'next' 'Ljdk/internal/ref/Cleaner;' @28  NULL (0 0)- private 'prev' 'Ljdk/internal/ref/Cleaner;' @32  NULL (0 e84d60c1)- private final 'thunk' 'Ljava/lang/Runnable;' @36  a 'java/nio/DirectByteBuffer$Deallocator'{0x00000007426b0608} (e84d60c1 9)
java.lang.ref.PhantomReference
{0x0000000742683ba0} - klass: 'java/lang/ref/PhantomReference'- ---- fields (total size 4 words):- private strict 'referent' 'Ljava/lang/Object;' @12  a 'com/hx/test02/Test02WeakReferenceAfterGc$Obj'{0x00000007404e1df0} (e809c3be e84d0770)- volatile strict 'queue' 'Ljava/lang/ref/ReferenceQueue;' @16  a 'java/lang/ref/ReferenceQueue'{0x0000000742683b80} (e84d0770 0)- volatile 'next' 'Ljava/lang/ref/Reference;' @20  NULL (0 e84d0774)- private transient strict 'discovered' 'Ljava/lang/ref/Reference;' @24  a 'java/lang/ref/PhantomReference'{0x0000000742683ba0} (e84d0774 0)

这里面的内容很多, 但是实际上我们只用关心 最后一个 "private strict 'referent' 'Ljava/lang/Object;' @12  a 'com/hx/test02/Test02WeakReferenceAfterGc$Obj'{0x00000007404e1df0} (e809c3be e84d0770)"

在之后的截图, 可能我这边会 去掉 部分与本主题无关的的引用的信息, 方便查看 , 并且都会加上备注

可以发现 gc 的时候找到了 我们的这个 “ref” 引用, 然后 这里是待处理的状态, 那么会怎么处理呢 ?

1.3 process_discovered_reflist(_discoveredPhantomRefs 处理之后

然后 断点下走一步, 我们再来看一下 _discoveredPhantomRefs 列表的数据

同样执行 上面查看 _discoveredPhantomRefs 列表的代码片, 得到如下结果

## 省略掉部分无关的 CleanerImpl$PhantomCleanableRef, Cleaner
java.lang.ref.PhantomReference
{0x0000000742683ba0} - klass: 'java/lang/ref/PhantomReference'- ---- fields (total size 4 words):- private strict 'referent' 'Ljava/lang/Object;' @12  NULL (0 e84d0770)- volatile strict 'queue' 'Ljava/lang/ref/ReferenceQueue;' @16  a 'java/lang/ref/ReferenceQueue'{0x0000000742683b80} (e84d0770 0)- volatile 'next' 'Ljava/lang/ref/Reference;' @20  NULL (0 e84d0774)- private transient strict 'discovered' 'Ljava/lang/ref/Reference;' @24  a 'java/lang/ref/PhantomReference'{0x0000000742683ba0} (e84d0774 0)

根据上面的 oop 的地址 0x0000000742683ba0 可以定位到上面的 PhantomReference 就是 "process_discovered_reflist(_discoveredPhantomRefs" 处理之后的数据了

可以发现 变化在于 referent 被置为 NULL 了

tips : 但是 在openjdk8对于 PhantomReference 的 process_phase3的处理是不会将 referent 置为 NULL 的, 参见 : http://hg.openjdk.java.net/jdk8/jdk8/hotspot/file/87ee5ee27509/src/share/vm/memory/referenceProcessor.cpp 249-252行

这个是由于 process_phase3 的过程中发现 referent 已经 gg 了, 然后就清理掉了 ref.referent 然后并且把它留在了 discoverList, 等待后续的步骤进行处理

然后后续 vm 将还存在的 discoverList 的引用关联到 Reference.pending 的列表上面

ReferenceHandler 将 Reference.pending 列表上的 Reference 放到 该Reference注册的 ReferenceQueue, 对应于我们这里 ref 会被放到 referenceQueue

然后 我们这里的消费线程, 从队列里面取引用, 拿到数据, 打印日志 "gc will collect ... "

这就是一个相对比较常规的流程

3. Test02WeakReferenceAfterGc$Obj 重写 finalize

增加一个 referenceProcessor.process_discovered_references 里面 process_discovered_reflist(_discoveredFinalRefs 断点

3.1 process_discovered_reflist(_discoveredFinalRefs 处理之前

打印 _discoveredFinalRefs 列表的数据如下

java.lang.ref.Finalizer
{0x00000007426cf9e8} - klass: 'java/lang/ref/Finalizer'- ---- fields (total size 5 words):- private strict 'referent' 'Ljava/lang/Object;' @12  a 'java/io/FileInputStream'{0x00000007404dbdb0} (e809b7b6 e84d073a)- volatile strict 'queue' 'Ljava/lang/ref/ReferenceQueue;' @16  a 'java/lang/ref/ReferenceQueue'{0x00000007426839d0} (e84d073a 0)- volatile 'next' 'Ljava/lang/ref/Reference;' @20  NULL (0 e84d6618)- private transient strict 'discovered' 'Ljava/lang/ref/Reference;' @24  a 'java/lang/ref/Finalizer'{0x00000007426b30c0} (e84d6618 e84de472)- private 'next' 'Ljava/lang/ref/Finalizer;' @28  a 'java/lang/ref/Finalizer'{0x00000007426f2390} (e84de472 e84d6618)- private 'prev' 'Ljava/lang/ref/Finalizer;' @32  a 'java/lang/ref/Finalizer'{0x00000007426b30c0} (e84d6618 0)
java.lang.ref.Finalizer
{0x00000007426b30c0} - klass: 'java/lang/ref/Finalizer'- ---- fields (total size 5 words):- private strict 'referent' 'Ljava/lang/Object;' @12  a 'java/io/FileInputStream'{0x00000007404e14d8} (e809c29b e84d073a)- volatile strict 'queue' 'Ljava/lang/ref/ReferenceQueue;' @16  a 'java/lang/ref/ReferenceQueue'{0x00000007426839d0} (e84d073a 0)- volatile 'next' 'Ljava/lang/ref/Reference;' @20  NULL (0 e84d2f87)- private transient strict 'discovered' 'Ljava/lang/ref/Reference;' @24  a 'java/lang/ref/Finalizer'{0x0000000742697c38} (e84d2f87 e84d9f3d)- private 'next' 'Ljava/lang/ref/Finalizer;' @28  a 'java/lang/ref/Finalizer'{0x00000007426cf9e8} (e84d9f3d e84d2f87)- private 'prev' 'Ljava/lang/ref/Finalizer;' @32  a 'java/lang/ref/Finalizer'{0x0000000742697c38} (e84d2f87 0)
java.lang.ref.Finalizer
{0x0000000742697c38} - klass: 'java/lang/ref/Finalizer'- ---- fields (total size 5 words):- private strict 'referent' 'Ljava/lang/Object;' @12  a 'com/hx/test02/Test02WeakReferenceAfterGc$Obj'{0x00000007404e1fa0} (e809c3f4 e84d073a)- volatile strict 'queue' 'Ljava/lang/ref/ReferenceQueue;' @16  a 'java/lang/ref/ReferenceQueue'{0x00000007426839d0} (e84d073a 0)- volatile 'next' 'Ljava/lang/ref/Reference;' @20  NULL (0 e84d2f87)- private transient strict 'discovered' 'Ljava/lang/ref/Reference;' @24  a 'java/lang/ref/Finalizer'{0x0000000742697c38} (e84d2f87 e84d6618)- private 'next' 'Ljava/lang/ref/Finalizer;' @28  a 'java/lang/ref/Finalizer'{0x00000007426b30c0} (e84d6618 0)- private 'prev' 'Ljava/lang/ref/Finalizer;' @32  NULL (0 0)

第三个 FinalReference 为 vm为 我们创建的 Obj 实例 o 创建的 Finalzer

3.2 process_discovered_reflist(_discoveredFinalRefs 处理之后

打印 _discoveredFinalRefs 列表的数据如下

java.lang.ref.Finalizer
{0x00000007426cf9e8} - klass: 'java/lang/ref/Finalizer'- ---- fields (total size 5 words):- private strict 'referent' 'Ljava/lang/Object;' @12  a 'java/io/FileInputStream'{0x0000000742770968} (e84ee12d e84d073a)- volatile strict 'queue' 'Ljava/lang/ref/ReferenceQueue;' @16  a 'java/lang/ref/ReferenceQueue'{0x00000007426839d0} (e84d073a 0)- volatile 'next' 'Ljava/lang/ref/Reference;' @20  NULL (0 e84d6618)- private transient strict 'discovered' 'Ljava/lang/ref/Reference;' @24  a 'java/lang/ref/Finalizer'{0x00000007426b30c0} (e84d6618 e84de472)- private 'next' 'Ljava/lang/ref/Finalizer;' @28  a 'java/lang/ref/Finalizer'{0x00000007426f2390} (e84de472 e84d6618)- private 'prev' 'Ljava/lang/ref/Finalizer;' @32  a 'java/lang/ref/Finalizer'{0x00000007426b30c0} (e84d6618 0)
java.lang.ref.Finalizer
{0x00000007426b30c0} - klass: 'java/lang/ref/Finalizer'- ---- fields (total size 5 words):- private strict 'referent' 'Ljava/lang/Object;' @12  a 'java/io/FileInputStream'{0x0000000742770988} (e84ee131 e84d073a)- volatile strict 'queue' 'Ljava/lang/ref/ReferenceQueue;' @16  a 'java/lang/ref/ReferenceQueue'{0x00000007426839d0} (e84d073a 0)- volatile 'next' 'Ljava/lang/ref/Reference;' @20  NULL (0 e84d2f87)- private transient strict 'discovered' 'Ljava/lang/ref/Reference;' @24  a 'java/lang/ref/Finalizer'{0x0000000742697c38} (e84d2f87 e84d9f3d)- private 'next' 'Ljava/lang/ref/Finalizer;' @28  a 'java/lang/ref/Finalizer'{0x00000007426cf9e8} (e84d9f3d e84d2f87)- private 'prev' 'Ljava/lang/ref/Finalizer;' @32  a 'java/lang/ref/Finalizer'{0x0000000742697c38} (e84d2f87 0)
java.lang.ref.Finalizer
{0x0000000742697c38} - klass: 'java/lang/ref/Finalizer'- ---- fields (total size 5 words):- private strict 'referent' 'Ljava/lang/Object;' @12  a 'com/hx/test02/Test02WeakReferenceAfterGc$Obj'{0x00000007427709a8} (e84ee135 e84d073a)- volatile strict 'queue' 'Ljava/lang/ref/ReferenceQueue;' @16  a 'java/lang/ref/ReferenceQueue'{0x00000007426839d0} (e84d073a 0)- volatile 'next' 'Ljava/lang/ref/Reference;' @20  NULL (0 e84d2f87)- private transient strict 'discovered' 'Ljava/lang/ref/Reference;' @24  a 'java/lang/ref/Finalizer'{0x0000000742697c38} (e84d2f87 e84d6618)- private 'next' 'Ljava/lang/ref/Finalizer;' @28  a 'java/lang/ref/Finalizer'{0x00000007426b30c0} (e84d6618 0)- private 'prev' 'Ljava/lang/ref/Finalizer;' @32  NULL (0 0)

可以看到 这个 我们创建的 Obj 实例 o 对应的 FinalReference 依然存在于 discoverList, 这就意味着之后 这个 FinalReference 之后会被添加到 它对应的 ReferenceQueue, 然后 FinalizerThread 线程 进行 finalize 的相关业务处理

注意, 这个 处理的过程的 process_phase3 这里传递的 clear_referent 为 false, 表示 需要将 Obj 实例 o, 复制到 存活区, FinalReference 依赖这个对象

3.3 process_discovered_reflist(_discoveredPhantomRefs 处理之前

打印 _discoveredPhantomRefs 列表的数据如下

## 省略掉部分无关的 CleanerImpl$PhantomCleanableRef, Cleaner
java.lang.ref.PhantomReference
{0x0000000742683bb8} - klass: 'java/lang/ref/PhantomReference'- ---- fields (total size 4 words):- private strict 'referent' 'Ljava/lang/Object;' @12  a 'com/hx/test02/Test02WeakReferenceAfterGc$Obj'{0x00000007404e1fa0} (e809c3f4 e84d0773)- volatile strict 'queue' 'Ljava/lang/ref/ReferenceQueue;' @16  a 'java/lang/ref/ReferenceQueue'{0x0000000742683b98} (e84d0773 0)- volatile 'next' 'Ljava/lang/ref/Reference;' @20  NULL (0 e84d0777)- private transient strict 'discovered' 'Ljava/lang/ref/Reference;' @24  a 'java/lang/ref/PhantomReference'{0x0000000742683bb8} (e84d0777 0)

这里的 PhantomReference 为 我们为 我们创建的 Obj 实例 o 创建的 PhantomReference

3.4 process_discovered_reflist(_discoveredPhantomRefs 处理之后

打印 _discoveredPhantomRefs 列表的数据如下

## 省略掉部分无关的 CleanerImpl$PhantomCleanableRef, Cleaner
# 找不到 0x0000000742683bb8 对应的 PhantomReference 了

这里我们发现 Obj 的实例 o 对应的  PhantomReference ref 被从 discoverList 里面移除了

这个是因为 上面处理 o 对应的 FinalReference 的时候, 将 o 复制到了 存活区, 因此 这里在 o 对应的 PhantomReference 处理 process_phase2 的时候, 因为 PhantomReference 还存活, 所以将 PhantomReference ref 移出了 discoverList

所以 在 第一个 System.gc 的时候 Obj 的实例 o 对应的 FinalReference 进入了 Finalizer.queue

但是 Obj 的实例 o 对应的 PhantomReference ref 没有进入其对应的 referenceQueue

3.5 第二次 System.gc process_discovered_reflist(_discoveredFinalRefs 处理之前

打印 _discoveredFinalRefs 列表的数据如下

java.lang.ref.Finalizer
{0x00000007422741d8} - klass: 'java/lang/ref/Finalizer'- ---- fields (total size 5 words):- private strict 'referent' 'Ljava/lang/Object;' @12  a 'java/lang/ClassLoader$NativeLibrary'{0x00000007426d3dd8} (e84da7bb e84487a3)- volatile strict 'queue' 'Ljava/lang/ref/ReferenceQueue;' @16  a 'java/lang/ref/ReferenceQueue'{0x0000000742243d18} (e84487a3 0)- volatile 'next' 'Ljava/lang/ref/Reference;' @20  NULL (0 e844b086)- private transient strict 'discovered' 'Ljava/lang/ref/Reference;' @24  a 'java/lang/ref/Finalizer'{0x0000000742258430} (e844b086 e84521bd)- private 'next' 'Ljava/lang/ref/Finalizer;' @28  a 'java/lang/ref/Finalizer'{0x0000000742290de8} (e84521bd e844b086)- private 'prev' 'Ljava/lang/ref/Finalizer;' @32  a 'java/lang/ref/Finalizer'{0x0000000742258430} (e844b086 0)
java.lang.ref.Finalizer
{0x0000000742258430} - klass: 'java/lang/ref/Finalizer'- ---- fields (total size 5 words):- private strict 'referent' 'Ljava/lang/Object;' @12  a 'java/lang/ClassLoader$NativeLibrary'{0x00000007426d3e00} (e84da7c0 e84487a3)- volatile strict 'queue' 'Ljava/lang/ref/ReferenceQueue;' @16  a 'java/lang/ref/ReferenceQueue'{0x0000000742243d18} (e84487a3 0)- volatile 'next' 'Ljava/lang/ref/Reference;' @20  NULL (0 e844b086)- private transient strict 'discovered' 'Ljava/lang/ref/Reference;' @24  a 'java/lang/ref/Finalizer'{0x0000000742258430} (e844b086 e844e83b)- private 'next' 'Ljava/lang/ref/Finalizer;' @28  a 'java/lang/ref/Finalizer'{0x00000007422741d8} (e844e83b 0)- private 'prev' 'Ljava/lang/ref/Finalizer;' @32  NULL (0 0)

没有了 Obj 实例对应的 o 的 FinalReference, 没有 强引用引用关联 该 FinalReference 了, 复制算法 Discover 不到该 FinalReference

3.6 第二次 System.gc process_discovered_reflist(_discoveredPhantomRefs 处理之前

打印 _discoveredPhantomRefs 列表的数据如下

## 省略掉部分无关的 CleanerImpl$PhantomCleanableRef, Cleaner
# 找不到 0x0000000742683bb8 对应的 PhantomReference 了

没有了 Obj 实例对应的 o 的 PhantomReference, 没有 强引用引用关联 该 PhantomReference了, 复制算法 Discover 不到该 PhantomReference

所以 第二次 gc 的时候, Obj 的实例 o 对应的 PhantomReference ref 没有进入其对应的 referenceQueue

经过这一次 gc, 一般情况下 Obj 实例 o, 对应的 FinalReference 已经处理了 finalize 的相关业务[sleep 3s], 并且 FinalizerThread 处理了该 FinalReference的后续流程, Obj 的实例 o, o 对应的 FinalReference, o 对应的 PhantomReference 都会被处理掉

4. 如何确保 o 对应的 PhantomReference 入队

相信看完了 上面的这一系列, 你应该有办法了吧

参考

https://hllvm-group.iteye.com/group/topic/34934

https://blog.csdn.net/KevinMite/article/details/83745080

01 PhantomReference没有进入ReferenceQueue相关推荐

  1. 如何成为一个区块链开发人员_成为开发人员是社会工作

    如何成为一个区块链开发人员 Times have changed since the old days when an IT professional was this typical shy per ...

  2. weakreference_Java中WeakReference,SoftReference,PhantomReference和Strong Reference之间的区别...

    weakreference 很长一段时间以来,WeakReference和SoftReference都已添加到Java API中,但是并不是每个Java程序员都熟悉它. 这意味着在Java中使用Wea ...

  3. Java中WeakReference,SoftReference,PhantomReference和Strong Reference之间的区别

    很长一段时间以来,WeakReference和SoftReference都已添加到Java API中,但是并不是每个Java程序员都熟悉它. 这意味着在Java中使用WeakReference和Sof ...

  4. Java源码:Reference与ReferenceQueue

    一:Reference与ReferenceQueue Reference的四种状态: Active:活跃,内存一开始分配的常有状态,垃圾收集器进行对该引用可达性分析后会进入Pending或Inacti ...

  5. 详细分析Android中的引用机制Reference(WeakReference、SoftReference、PhantomReference)

    目录 1.前言 2.四种引用 3.java.lang.ref 4.Reference 5.ReferenceQueue.enqueue(Reference) 6.ReferenceQueue.isEn ...

  6. Reference定义(PhantomReference,Cleaner)

    Java NIO ByteBuffer详解:[url]http://donald-draper.iteye.com/blog/2357084[/url] MappedByteBuffer定义:[url ...

  7. java 源码系列 - 带你读懂 Reference 和 ReferenceQueue

    java 源码系列 - 带你读懂 Reference 和 ReferenceQueue https://blog.csdn.net/gdutxiaoxu/article/details/8073858 ...

  8. 深入理解StrongReference,SoftReference, WeakReference和PhantomReference

    Java 中一共有 4 种类型的引用 : StrongReference. SoftReference. WeakReference 以及 PhantomReference (传说中的幽灵引用 呵呵) ...

  9. Java ~ Reference ~ PhantomReference【源码】

    前言 文章 相关系列:<Java ~ Reference[目录]>(持续更新) 相关系列:<Java ~ Reference ~ PhantomReference[源码]>(学 ...

最新文章

  1. 硬刚一周,3W字总结,一年的经验告诉你如何准备校招!
  2. Scala集合体系:可变集合和不可变集合
  3. Apache状态监测集重启
  4. hutool 读取扩展名文件_用卓语言实现中文编程显示隐藏文件扩展名
  5. 【ARM】Tiny4412裸板编程之MMU(段 16M)
  6. 【Linux】一步一步学Linux——iptables命令(186)
  7. MySQL高级之查询优化(索引失效)
  8. SAP Spartacus 服务器端渲染的三种可能情形
  9. 计算机一级上机考试试题题库,2016年计算机一级上机考试题库
  10. 什么是静态,静态有什么作用呢?
  11. 量子计算机 长生不老,这种准粒子“长生不老”,有望提升量子计算机性能
  12. redmine 自己定义字段mysql表结构
  13. eclipse经常出现弹窗Refreshing workspace
  14. numpy库的安装方法
  15. 以锅炉安全为例,台账管理在安全建设中的作用
  16. 寻找春天nbsp;九宫格日记-2014.04.26
  17. Interlocked.Increment 方法 和Interlocked.Decrement 方法作用
  18. [PPPOE]PPPD源码分析
  19. 个人自建数据库和云数据库有什么区别?
  20. 安卓证书免费在线制作工具

热门文章

  1. KVM虚拟机快速入门
  2. 计算机系统盘突然爆满,电脑c盘突然爆满是怎么个情况_电脑c盘和d盘的区别
  3. JVM学习四:垃圾收集器与内存回收策略
  4. 关于自行修改人人商城模板文件目录指引
  5. ar 微信小程序_微信小程序开放AR功能,全面提升交互体验
  6. 内置在maven项目的服务器,IDEA使用maven中tomcat插件来启动服务器配置
  7. 多源异构数据融合平台
  8. ChromeOptions--禁止加载图片
  9. 蓝牙BLE芯片PHY6222之烧录以及调试
  10. Coding and Paper Letter(七十)