本篇博客继续上一篇ReferenceProcessor 讲解ReferenceProcessor的其他关键方法的实现。
1、process_discovered_reflist
process_discovered_reflist用于对指定的DiscoveredList做过滤,移除referent是存活的Reference实例,然后根据参数clear_referent,要么将referent属性置为null,要么将referent对象标记为存活的,如果是discoveredSoftRefs则首先移除那些referent对象是死的但是ReferencePolicy判断不能清除的Reference实例。其实现如下:
size_t
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;
//如果查找过程是并行的,则必须平衡refs_lists中的各个DiscoveredList
bool must_balance = _discovery_is_mt;
//ParallelRefProcBalancingEnabled默认为true,表示允许平衡各个处理队列
if ((mt_processing && ParallelRefProcBalancingEnabled) ||
must_balance) {
balance_queues(refs_lists);
}
//统计总的Reference的个数
size_t total_list_count = total_count(refs_lists);
if (PrintReferenceGC && PrintGCDetails) {
gclog_or_tty->print(", %u refs", total_list_count);
}
// Phase 1 只适用于SoftReferences对应的DiscoveredList
if (policy != NULL) {
if (mt_processing) {
RefProcPhase1Task phase1(*this, refs_lists, policy, true /*marks_oops_alive*/);
task_executor->execute(phase1);
} else {
//如果policy不为空,则认为refs_lists就是_discoveredSoftRefs
for (uint i = 0; i < _max_num_q; i++) {
process_phase1(refs_lists[i], policy,
is_alive, keep_alive, complete_gc);
}
}
} else { // policy为NULL,则refs_lists不等于_discoveredSoftRefs
assert(refs_lists != _discoveredSoftRefs,
"Policy must be specified for soft references.");
}
// Phase 2:
//遍历refs_lists,移除所有referent是存活的Reference实例
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:
//遍历refs_lists,根据参数clear_referent做适当处理
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);
}
}
//返回移除前的Reference实例的总的个数
return total_list_count;
}
//统计总的Reference实例的个数
size_t ReferenceProcessor::total_count(DiscoveredList lists[]) {
size_t total = 0;
for (uint i = 0; i < _max_num_q; ++i) {
total += lists[i].length();
}
return total;
}
//只适用于SoftReferences对应的DiscoveredList,会遍历所有的SoftReference,找到所有的referent对象是死的但是通过ReferencePolicy
//判断不需要清理的SoftReference实例,将其标记为Active状态,将referent对象标记为存活的
void
ReferenceProcessor::process_phase1(DiscoveredList& refs_list,
ReferencePolicy* policy,
BoolObjectClosure* is_alive,
OopClosure* keep_alive,
VoidClosure* complete_gc) {
assert(policy != NULL, "Must have a non-NULL policy");
//创建一个迭代器
DiscoveredListIterator iter(refs_list, keep_alive, is_alive);
//执行遍历
while (iter.has_next()) {
//获取当前Reference的discovered及referent属性的内存地址和值
iter.load_ptrs(DEBUG_ONLY(!discovery_is_atomic() /* allow_null_referent */));
//判断referent对象是否存活
bool referent_is_dead = (iter.referent() != NULL) && !iter.is_referent_alive();
//如果referent对象是死的,即没有其他的强引用了,且暂不清理该Reference实例
if (referent_is_dead &&
!policy->should_clear_reference(iter.obj(), _soft_ref_timestamp_clock)) {
if (TraceReferenceGC) {
gclog_or_tty->print_cr("Dropping reference (" INTPTR_FORMAT ": %s" ") by policy",
(void *)iter.obj(), iter.obj()->klass()->internal_name());
}
//将该Reference实例从DiscoveredList中移除
iter.remove();
//将该Reference实例标记为Active状态,即将next属性置为null
iter.make_active();
//让该referent对象是存活的
iter.make_referent_alive();
//切换到下一个Reference实例
iter.move_to_next();
} else {
//不做处理,然后该Reference实例就会被ReferenceHandle Thread处理掉
iter.next();
}
}
// Close the reachable set
complete_gc->do_void();
}
void DiscoveredListIterator::make_active() {
if (UseG1GC) {
//G1下需要调用额外的bs方法
HeapWord* next_addr = java_lang_ref_Reference::next_addr(_ref);
if (UseCompressedOops) {
oopDesc::bs()->write_ref_field_pre((narrowOop*)next_addr, NULL);
} else {
oopDesc::bs()->write_ref_field_pre((oop*)next_addr, NULL);
}
}
//将next属性置为NULL
java_lang_ref_Reference::set_next_raw(_ref, NULL);
}
// Make the referent alive.
inline void make_referent_alive() {
if (UseCompressedOops) {
_keep_alive->do_oop((narrowOop*)_referent_addr);
} else {
_keep_alive->do_oop((oop*)_referent_addr);
}
}
//从DiscoveredList中移除referent是存活的Reference实例,并行处理时还需要移除referent是null或者next属性不为空的Reference实例
inline void process_phase2(DiscoveredList& refs_list,
BoolObjectClosure* is_alive,
OopClosure* keep_alive,
VoidClosure* complete_gc) {
if (discovery_is_atomic()) {
//非并发场景下
pp2_work(refs_list, is_alive, keep_alive);
} else {
//并发场景下
assert(complete_gc != NULL, "Error");
pp2_work_concurrent_discovery(refs_list, is_alive,
keep_alive, complete_gc);
}
}
void
ReferenceProcessor::pp2_work(DiscoveredList& refs_list,
BoolObjectClosure* is_alive,
OopClosure* keep_alive) {
assert(discovery_is_atomic(), "Error");
//执行遍历
DiscoveredListIterator iter(refs_list, keep_alive, is_alive);
while (iter.has_next()) {
iter.load_ptrs(DEBUG_ONLY(false /* allow_null_referent */));
DEBUG_ONLY(oop next = java_lang_ref_Reference::next(iter.obj());)
assert(next == NULL, "Should not discover inactive Reference");
if (iter.is_referent_alive()) {
//如果referent对象是存活的
if (TraceReferenceGC) {
gclog_or_tty->print_cr("Dropping strongly reachable reference (" INTPTR_FORMAT ": %s)",
(void *)iter.obj(), iter.obj()->klass()->internal_name());
}
//将当前Reference实例从DiscoveredList中移除
iter.remove();
//将referent对象标记成存活的
iter.make_referent_alive();
//切换到下一个Reference实例
iter.move_to_next();
} else {
iter.next();
}
}
}
void
ReferenceProcessor::pp2_work_concurrent_discovery(DiscoveredList& refs_list,
BoolObjectClosure* is_alive,
OopClosure* keep_alive,
VoidClosure* complete_gc) {
assert(!discovery_is_atomic(), "Error");
DiscoveredListIterator iter(refs_list, keep_alive, is_alive);
while (iter.has_next()) {
iter.load_ptrs(DEBUG_ONLY(true /* allow_null_referent */));
HeapWord* next_addr = java_lang_ref_Reference::next_addr(iter.obj());
oop next = java_lang_ref_Reference::next(iter.obj());
//next属性如果不为空,则指向它自己
if ((iter.referent() == NULL || iter.is_referent_alive() ||
next != NULL)) {
assert(next->is_oop_or_null(), "bad next field");
// Remove Reference object from list
iter.remove();
// Trace the cohorts
iter.make_referent_alive();
//多了一步,让next属性即它自己保持alive
if (UseCompressedOops) {
keep_alive->do_oop((narrowOop*)next_addr);
} else {
keep_alive->do_oop((oop*)next_addr);
}
iter.move_to_next();
} else {
iter.next();
}
}
// Now close the newly reachable set
complete_gc->do_void();
}
//遍历DiscoveredList,根据参数clear_referent,要么将referent属性置为null,要么将referent对象标记为存活的
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()) {
//将当前Reference实例标记为存活的
iter.update_discovered();
iter.load_ptrs(DEBUG_ONLY(false /* allow_null_referent */));
if (clear_referent) {
//将referent属性置为null
iter.clear_referent();
} else {
//将referent属性标记为存活的
iter.make_referent_alive();
}
if (TraceReferenceGC) {
gclog_or_tty->print_cr("Adding %sreference (" INTPTR_FORMAT ": %s) as pending",
clear_referent ? "cleared " : "",
(void *)iter.obj(), iter.obj()->klass()->internal_name());
}
assert(iter.obj()->is_oop(UseConcMarkSweepGC), "Adding a bad reference");
iter.next();
}
// Remember to update the next pointer of the last ref.
iter.update_discovered();
// Close the reachable set
complete_gc->do_void();
}
void DiscoveredListIterator::clear_referent() {
oop_store_raw(_referent_addr, NULL);
}
inline void update_discovered() {
//_prev_next实际指向当前Reference实例
if (UseCompressedOops) {
if (!oopDesc::is_null(*(narrowOop*)_prev_next)) {
_keep_alive->do_oop((narrowOop*)_prev_next);
}
} else {
if (!oopDesc::is_null(*(oop*)_prev_next)) {
_keep_alive->do_oop((oop*)_prev_next);
}
}
}
其调用链如下:
image.png2、process_phaseJNI
process_phaseJNI用于处理JNIHandleBlock中保存的JNI弱引用oop,如果这个oop是存活的则将其标记为存活的,如果说是死的,则将其置为null,其实现如下:
void ReferenceProcessor::process_phaseJNI(BoolObjectClosure* is_alive,
OopClosure* keep_alive,
VoidClosure* complete_gc) {
JNIHandles::weak_oops_do(is_alive, keep_alive);
complete_gc->do_void();
}
void JNIHandles::weak_oops_do(BoolObjectClosure* is_alive, OopClosure* f) {
_weak_global_handles->weak_oops_do(is_alive, f);
}
void JNIHandleBlock::weak_oops_do(BoolObjectClosure* is_alive,
OopClosure* f) {
//遍历所有保存弱引用的JNIBlock
for (JNIHandleBlock* current = this; current != NULL; current = current->_next) {
assert(current->pop_frame_link() == NULL,
"blocks holding weak global JNI handles should not have pop frame link set");
//遍历JNIBlock中保存的所有弱引用oop
for (int index = 0; index < current->_top; index++) {
oop* root = &(current->_handles)[index];
oop value = *root;
// traverse heap pointers only, not deleted handles or free list pointers
if (value != NULL && Universe::heap()->is_in_reserved(value)) {
if (is_alive->do_object_b(value)) {
//如果这个oop是存活的,则将其打标为存活的
f->do_oop(root);
} else {
if (TraceReferenceGC) {
tty->print_cr("Clearing JNI weak reference (" INTPTR_FORMAT ")", root);
}
//如果oop不是存活的,则将其置为null
*root = NULL;
}
}
}
//只有当前JNIBlock是满的才会遍历下一个JNIBlock
if (current->_top < block_size_in_oops) {
break;
}
}
//发布JVMTI事件
JvmtiExport::weak_oops_do(is_alive, f);
}
其调用链如下:
3、process_discovered_references
process_discovered_references是实际对外的用于处理查找出来的位于不同类型的DiscoveredList中的Reference实例,底层实际调用process_discovered_reflist和process_phaseJNI方法,其实现如下:
ReferenceProcessorStats ReferenceProcessor::process_discovered_references(
BoolObjectClosure* is_alive,
OopClosure* keep_alive,
VoidClosure* complete_gc,
AbstractRefProcTaskExecutor* task_executor,
GCTimer* gc_timer,
GCId gc_id) {
NOT_PRODUCT(verify_ok_to_handle_reflists());
assert(!enqueuing_is_done(), "If here enqueuing should not be complete");
//停止Reference实例查找
disable_discovery();
//使用SoftReference的clock属性更新_soft_ref_timestamp_clock,因为之前并发查找的时候可能通过反射或者Unsafe改变了clock属性
_soft_ref_timestamp_clock = java_lang_ref_SoftReference::clock();
bool trace_time = PrintGCDetails && PrintReferenceGC;
// Soft references
size_t soft_count = 0;
{
GCTraceTime tt("SoftReference", trace_time, false, gc_timer, gc_id);
soft_count =
//处理_discoveredSoftRefs,注意传入的clear_referent的值为true,除_discoveredSoftRefs传入的ReferencePolicy有具体值外,其他类型的都是传NULL
process_discovered_reflist(_discoveredSoftRefs, _current_soft_ref_policy, true,
is_alive, keep_alive, complete_gc, task_executor);
}
update_soft_ref_master_clock();
// Weak references
size_t weak_count = 0;
{
GCTraceTime tt("WeakReference", trace_time, false, gc_timer, gc_id);
weak_count =
//处理_discoveredSoftRefs,注意传入的clear_referent的值为true
process_discovered_reflist(_discoveredWeakRefs, NULL, true,
is_alive, keep_alive, complete_gc, task_executor);
}
// Final references
size_t final_count = 0;
{
GCTraceTime tt("FinalReference", trace_time, false, gc_timer, gc_id);
//处理_discoveredFinalRefs,注意传入的clear_referent的值为false,因为后续需要调用referent对象的finalize方法
final_count =
process_discovered_reflist(_discoveredFinalRefs, NULL, false,
is_alive, keep_alive, complete_gc, task_executor);
}
// Phantom references
size_t phantom_count = 0;
{
GCTraceTime tt("PhantomReference", trace_time, false, gc_timer, gc_id);
///处理_discoveredPhantomRefs,注意传入的clear_referent的值为false,子类可能需要使用referent对象
phantom_count =
process_discovered_reflist(_discoveredPhantomRefs, NULL, false,
is_alive, keep_alive, complete_gc, task_executor);
//处理_discoveredCleanerRefs,将返回的数据和phantom_count算在一起
phantom_count +=
process_discovered_reflist(_discoveredCleanerRefs, NULL, true,
is_alive, keep_alive, complete_gc, task_executor);
}
{
GCTraceTime tt("JNI Weak Reference", trace_time, false, gc_timer, gc_id);
if (task_executor != NULL) {
task_executor->set_single_threaded_mode();
}
//处理JNI的弱引用
process_phaseJNI(is_alive, keep_alive, complete_gc);
}
//ReferenceProcessorStats就是一个简单的数据结构
return ReferenceProcessorStats(soft_count, weak_count, final_count, phantom_count);
}
void disable_discovery() { _discovering_refs = false; }
void ReferenceProcessor::update_soft_ref_master_clock() {
jlong now = os::javaTimeNanos() / NANOSECS_PER_MILLISEC;
jlong soft_ref_clock = java_lang_ref_SoftReference::clock();
assert(soft_ref_clock == _soft_ref_timestamp_clock, "soft ref clocks out of sync");
NOT_PRODUCT(
if (now < _soft_ref_timestamp_clock) {
warning("time warp: "INT64_FORMAT" to "INT64_FORMAT,
_soft_ref_timestamp_clock, now);
}
)
if (now > _soft_ref_timestamp_clock) {
//重置_soft_ref_timestamp_clock并更新clock属性
_soft_ref_timestamp_clock = now;
java_lang_ref_SoftReference::set_clock(now);
}
}
其调用链如下:
image.png该方法是在enqueue_discovered_references之前调用的,参考CMSCollector::refProcessingWork的实现。
4、 preclean_discovered_references
该方法用于从各类型的DiscoveredList中移除referent属性是存活的或者是null或者next属性不为null的Reference实例,移除逻辑等同于process_phase2方法的实现,只有CMSCollector调用,其调用链如下:
其实现如下:
//从各类型的DiscoveredList中移除referent属性是存活的或者是null或者next属性不为null的Reference实例,移除逻辑等同于process_phase2方法的实现
//各类型的DiscoveredList的处理顺序是随意的,可以并发执行
void ReferenceProcessor::preclean_discovered_references(
BoolObjectClosure* is_alive,
OopClosure* keep_alive,
VoidClosure* complete_gc,
YieldClosure* yield,
GCTimer* gc_timer,
GCId gc_id) {
NOT_PRODUCT(verify_ok_to_handle_reflists());
// Soft references
{
GCTraceTime tt("Preclean SoftReferences", PrintGCDetails && PrintReferenceGC,
false, gc_timer, gc_id);
for (uint i = 0; i < _max_num_q; i++) {
if (yield->should_return()) {
return;
}
preclean_discovered_reflist(_discoveredSoftRefs[i], is_alive,
keep_alive, complete_gc, yield);
}
}
// Weak references
{
GCTraceTime tt("Preclean WeakReferences", PrintGCDetails && PrintReferenceGC,
false, gc_timer, gc_id);
for (uint i = 0; i < _max_num_q; i++) {
if (yield->should_return()) {
return;
}
preclean_discovered_reflist(_discoveredWeakRefs[i], is_alive,
keep_alive, complete_gc, yield);
}
}
// Final references
{
GCTraceTime tt("Preclean FinalReferences", PrintGCDetails && PrintReferenceGC,
false, gc_timer, gc_id);
for (uint i = 0; i < _max_num_q; i++) {
if (yield->should_return()) {
return;
}
preclean_discovered_reflist(_discoveredFinalRefs[i], is_alive,
keep_alive, complete_gc, yield);
}
}
// Phantom references
{
GCTraceTime tt("Preclean PhantomReferences", PrintGCDetails && PrintReferenceGC,
false, gc_timer, gc_id);
for (uint i = 0; i < _max_num_q; i++) {
if (yield->should_return()) {
return;
}
preclean_discovered_reflist(_discoveredPhantomRefs[i], is_alive,
keep_alive, complete_gc, yield);
}
for (uint i = 0; i < _max_num_q; i++) {
if (yield->should_return()) {
return;
}
preclean_discovered_reflist(_discoveredCleanerRefs[i], is_alive,
keep_alive, complete_gc, yield);
}
}
}
void
ReferenceProcessor::preclean_discovered_reflist(DiscoveredList& refs_list,
BoolObjectClosure* is_alive,
OopClosure* keep_alive,
VoidClosure* complete_gc,
YieldClosure* yield) {
//执行遍历
DiscoveredListIterator iter(refs_list, keep_alive, is_alive);
while (iter.has_next()) {
//获取当前Reference实例的discovered和referent属性
iter.load_ptrs(DEBUG_ONLY(true /* allow_null_referent */));
oop obj = iter.obj();
//获取当前Reference实例的next属性
oop next = java_lang_ref_Reference::next(obj);
//如果referent属性为null或者是存活的或者next属性不为空,即当前Reference实例不是Active状态
if (iter.referent() == NULL || iter.is_referent_alive() ||
next != NULL) {
if (TraceReferenceGC) {
gclog_or_tty->print_cr("Precleaning Reference (" INTPTR_FORMAT ": %s)",
(void *)iter.obj(), iter.obj()->klass()->internal_name());
}
//将当前Reference实例从DiscoveredList中移除
iter.remove();
//将referent属性标记为存活的
iter.make_referent_alive();
//将next属性标记为存活的
if (UseCompressedOops) {
narrowOop* next_addr = (narrowOop*)java_lang_ref_Reference::next_addr(obj);
keep_alive->do_oop(next_addr);
} else {
oop* next_addr = (oop*)java_lang_ref_Reference::next_addr(obj);
keep_alive->do_oop(next_addr);
}
//切换到下一个Reference实例
iter.move_to_next();
} else {
iter.next();
}
}
// Close the reachable set
complete_gc->do_void();
}
5、clean_up_discovered_references
该方法用于从各类型的DiscoveredList中移除referent属性为null或者next属性不为null的Reference实例,其实现与之前的preclean_discovered_references等遍历处理方法大同小异,如下:
void ReferenceProcessor::clean_up_discovered_references() {
// loop over the lists
for (uint i = 0; i < _max_num_q * number_of_subclasses_of_ref(); i++) {
if (TraceReferenceGC && PrintGCDetails && ((i % _max_num_q) == 0)) {
gclog_or_tty->print_cr(
"\nScrubbing %s discovered list of Null referents",
list_name(i));
}
clean_up_discovered_reflist(_discovered_refs[i]);
}
}
void ReferenceProcessor::clean_up_discovered_reflist(DiscoveredList& refs_list) {
assert(!discovery_is_atomic(), "Else why call this method?");
//执行遍历
DiscoveredListIterator iter(refs_list, NULL, NULL);
while (iter.has_next()) {
//获取当前Reference实例的discovered和referent属性
iter.load_ptrs(DEBUG_ONLY(true /* allow_null_referent */));
//获取当前Reference实例的next属性
oop next = java_lang_ref_Reference::next(iter.obj());
assert(next->is_oop_or_null(), "bad next field");
//如果referent属性为null,即被清除了,或者next属性不为null,即当前Reference实例不是Active状态
if (iter.referent() == NULL || next != NULL) {
debug_only(
if (PrintGCDetails && TraceReferenceGC) {
gclog_or_tty->print_cr("clean_up_discovered_list: Dropping Reference: "
INTPTR_FORMAT " with next field: " INTPTR_FORMAT
" and referent: " INTPTR_FORMAT,
(void *)iter.obj(), (void *)next, (void *)iter.referent());
}
)
//将Reference从DiscoveredList中移除
iter.remove();
//切换到下一个Reference实例
iter.move_to_next();
} else {
iter.next();
}
}
}
const char* ReferenceProcessor::list_name(uint i) {
assert(i >= 0 && i <= _max_num_q * number_of_subclasses_of_ref(),
"Out of bounds index");
int j = i / _max_num_q;
switch (j) {
case 0: return "SoftRef";
case 1: return "WeakRef";
case 2: return "FinalRef";
case 3: return "PhantomRef";
case 4: return "CleanerRef";
}
ShouldNotReachHere();
return NULL;
}
该方法的调用链如下:
image.png6、abandon_partial_discovery
该方法用于清空所有DiscoveredList中的Reference实例,将Reference实例的discovered属性置为null,将DiscoveredList恢复成初始状态,其实现如下:
void ReferenceProcessor::abandon_partial_discovery() {
// loop over the lists
for (uint i = 0; i < _max_num_q * number_of_subclasses_of_ref(); i++) {
if (TraceReferenceGC && PrintGCDetails && ((i % _max_num_q) == 0)) {
gclog_or_tty->print_cr("\nAbandoning %s discovered list", list_name(i));
}
abandon_partial_discovered_list(_discovered_refs[i]);
}
}
void
ReferenceProcessor::abandon_partial_discovered_list(DiscoveredList& refs_list) {
clear_discovered_references(refs_list);
}
void
ReferenceProcessor::clear_discovered_references(DiscoveredList& refs_list) {
oop obj = NULL;
oop next = refs_list.head();
//遍历DiscoveredList,将所有的Reference实例的discovered属性置为null
while (next != obj) {
obj = next;
next = java_lang_ref_Reference::discovered(obj);
java_lang_ref_Reference::set_discovered_raw(obj, NULL);
}
//将DiscoveredList恢复成初始状态
refs_list.set_head(NULL);
refs_list.set_length(0);
}
该方法的调用链如下,注意该方法只能在安全点的时候调用:
image.png7、总结
在垃圾回收器遍历所有Java对象时,判断该对象是Reference实例就会调用discover_reference方法将该实例加入到对应类型的 DiscoveredList中,遍历结束会调用process_discovered_references对各类型的DiscoveredList中包含的Reference实例和JNIBlock中包含的弱引用oop做必要的处理,如移除referent属性是存活的Reference实例,最后调用enqueue_discovered_references方法将各类型的DiscoveredList包含的Reference实例加入到由Reference静态属性pending和实例属性discovered构成的一个链表中并更新静态pending属性指向最新的链表头,更新Reference实例的next属性指向它自己,即将Reference实例标记成Pending状态,处理完成后再将DiscoveredList恢复成初始状态。然后处于Pending状态的Reference实例就会被ReferenceHandler从链表中移除加入到Reference实例创建时传入的ReferenceQueue中,如果是Cleaner实例则调用该实例的clean方法,调用方可以通过遍历ReferenceQueue知道有哪些Reference实例的referent属性被垃圾回收处理掉了。
网友评论