java引用疑问

java引用疑问

java

引用:
深入分析Object.finalize方法的实现原理 -
Java软引用究竟什么时候被回收 -
gc过程中reference对象的处理 - ImportNew
java中针对Reference的实现和相应的执行过程 – I flym


前提:
WeakReference(T referent, ReferenceQueue 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对象置空。

你可能感兴趣的:(java引用疑问)