美文网首页
java引用疑问

java引用疑问

作者: lesline | 来源:发表于2019-03-14 09:50 被阅读0次

    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对象置空。

    相关文章

      网友评论

          本文标题:java引用疑问

          本文链接:https://www.haomeiwen.com/subject/iygfmqtx.html