java引用疑问
java
引用:
深入分析Object.finalize方法的实现原理 - 简书
Java软引用究竟什么时候被回收 - 简书
gc过程中reference对象的处理 - ImportNew
java中针对Reference的实现和相应的执行过程 – I flym
前提:
WeakReference(T referent, ReferenceQueue<? super T> q):与上面的构造方法比较,多了个ReferenceQueue,在对象被回收后,会把弱引用对象,也就是WeakReference对象或者其子类的对象,放入队列ReferenceQueue中,注意不是被弱引用的对象,被弱引用的对象已经被回收了。
问题:
1、private static Finalizer unfinalized= null; //做什么用?
unfinalized链表: 维护了一个未执行finalize方法的reference链表。维护静态字段unfinalized的目的是为了一直保持对未执行finalize方法的reference的强引用,防止被gc回收掉。
第一次GC时,会把该finalizee对应的reference放到Finalizer的refereneQueue中;接着,FinalizerThread来执行finalizee的finalize方法,并把当前Finalizer从unfinalized中剔除。当下一次GC发生时,由于unfinalized已经不再持有该对象的referent,故该对象被直接回收掉。
2、如果没有unfinalized,会如何?
unfinalized对referene是强引用,但没有对原对象没有强引用,为什么可以保证原对象不被回收?
refereneQueue队列中referene类型的,unfinalized也是referene类型的,没有强引用到原对象。
回答:对强引用的理解有误,referene与referent的引用 是强引用,即unfinalized-> referene-> referent 是强引用。
未实现finalize方法的对象没有强引用。
容易引起误解的是:weak、soft引用中的queue与referent的引用也是强引用,但这是在referent(原始对象)删除后再放到queue中。
疑问:WeakReference SoftReference 对referent置为null,进入到queue的顺序不一致?
有以下说法:
WeakReference对象进入到queue之后,相应的referent为null.
SoftReference对象,如果对象在内存足够时,不会进入到queue,自然相应的reference不会为null.如果需要被处理(内存不够或其它策略),则置相应的referent为null,然后进入到queue.
FinalReference对象,因为需要调用其finalize对象,因此其reference即使入queue,其referent也不会为null,即不会clear掉.
PhantomReference对象,因为本身get实现为返回null.因此clear的作用不是很大.因为不管enqueue还是没有,都不会清除掉.
上述方法有误:
weak_count = process_discovered_reflist(_discoveredWeakRefs, NULL, true,is_alive, keep_alive, complete_gc, task_executor);
第三个参数clear_referent传true,表示先清理referent再处理pending链
源码分析
gc过程中reference对象的处理 - ImportNew
垃圾回收过程
标计清除:先搜索需处理的引用(其中第三步会清除referent),再把引用链附到pending对象上
void CMSCollector::refProcessingWork(bool asynch, bool clear_all_soft_refs) {
ReferenceProcessor* rp = ref_processor();
ReferenceProcessorStats stats;
//正式的引用处理过程
stats = rp->process_discovered_references(&_is_alive_closure,
&cmsKeepAliveClosure,
&cmsDrainMarkingStackClosure,
NULL,
_gc_timer_cm,
_gc_tracer_cm->gc_id());
//正式的引用链重新附到pending对象上
rp->enqueue_discovered_references(NULL);
}
CMS执行部分
在之前的引用入栈之后,在cms的FinalMarking阶段,会进行各项引用的处理工作,即重新处理引用信息,然后附到pending上去。整个处理逻辑以及调用链如下所示:
FinalMarking 最终标识阶段
VM_CMS_Final_Remark 进行最终标识这一步骤
do_CMS_operation 进行指定的操作
CMS_op_checkpointRootsFinal 指定步骤语义
checkpointRootsFinal
checkpointRootsFinalWork
refProcessingWork 整个引用处理逻辑
enqueue_discovered_references 对enqueue_discovered_ref_helper的封装调用
enqueue_discovered_ref_helper 辅助工具类 找到pending节点,准备替换,然后又切换回来
enqueue_discovered_reflists 正式的替换pending节点
JDK源码方法:ReferenceProcessor::enqueue_discovered_reflist
问:weakRefrence里的对象是什么时候回收的?
答:在process_phase3方法中 执行 iter.clear_referent();// NULL out referent pointer 方法将referent对象置空。
清空对象过程:
process_discovered_references
process_discovered_reflist
process_phase3
不同的引用调用process_discovered_reflist方法时 clear_referent参数不同,
soft weak references时clear_referent传true,Final Phantom references为false.
表示:soft weak references是先pending,再清除referent
weak_count = process_discovered_reflist(_discoveredWeakRefs, NULL, true,
is_alive, keep_alive, complete_gc, task_executor);
final_count =process_discovered_reflist(_discoveredFinalRefs, NULL, false,
is_alive, keep_alive, complete_gc, task_executor);
clear_referent参数
ReferenceProcessorStats ReferenceProcessor::process_discovered_references(
BoolObjectClosure* is_alive,
OopClosure* keep_alive,
VoidClosure* complete_gc,
AbstractRefProcTaskExecutor* task_executor,
GCTimer* gc_timer) {
NOT_PRODUCT(verify_ok_to_handle_reflists());
// Soft references
size_t soft_count = 0;
{
GCTraceTime tt("SoftReference", trace_time, false, gc_timer);
soft_count =
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);
weak_count =
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);
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);
phantom_count =
process_discovered_reflist(_discoveredPhantomRefs, NULL, false,
is_alive, keep_alive, complete_gc, task_executor);
}
}
ReferenceProcessor::process_discovered_reflist(
DiscoveredList refs_lists[],
ReferencePolicy* policy,
bool clear_referent,
BoolObjectClosure* is_alive,
OopClosure* keep_alive,
VoidClosure* complete_gc,
AbstractRefProcTaskExecutor* task_executor)
{...
// Phase 3:
// . Traverse the list and process referents as appropriate.
if (mt_processing) { //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);
}
}
...
}
// 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.update_discovered();
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();
}
if (TraceReferenceGC) {
gclog_or_tty->print_cr("Adding %sreference (" INTPTR_FORMAT ": %s) as pending",
clear_referent ? "cleared " : "",
iter.obj(), iter.obj()->blueprint()->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();
}
在process_phase3方法中 执行 iter.clear_referent();// NULL out referent pointer 方法将referent对象置空。
网友评论