前言
最近 看到一篇文章, 然後 基於改文章的代碼, 做了一些 調整, 然後 發現了一些 奇怪的事情, 並稍微整理了一下 原因
該文章地址 : 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 <[email protected]>
* @version 1.0
* @date 2019-10-14 11:23
*/
public class Test02WeakReferenceAfterGc {
// Test02WeakReferenceAfterGc
// refer : https://hllvm-group.iteye.com/group/topic/34934
public 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();
// consumer
new 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 <[email protected]>
* @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();
// }
@Override
public 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 == NULL
assert(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 pointer
iter.clear_referent();
} else {
// keep the referent around
iter.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 set
complete_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: RUNNABLE
JavaThread state: _thread_blocked
Thread: 0x00007fa786803800 [0x2403] State: _at_safepoint _has_called_back 0 _at_poll_safepoint 0
$jerry : thread->print_stack()
JavaThread state: _thread_blocked
at 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