Hotspot 垃圾回收之ReferenceProcessor(一) 源码解析

   目录

一、ReferencePolicy

1、定义

2、LRUMaxHeapPolicy / LRUCurrentHeapPolicy

二、DiscoveredList

三、DiscoveredListIterator

四、ReferenceProcessor

1、定义

2、referenceProcessor_init / 构造方法

3、discover_reference

4、enqueue_discovered_references

5、balance_all_queues


本篇博客开始讲解用于java.lang.Reference实例清理的ReferenceProcessor类和相关内的实现。

一、ReferencePolicy

1、定义

      ReferencePolicy类的定义在hotspot\src\share\vm\memory\referencePolicy.hpp中,用来决定是否应该清理一个软引用,其定义就两个方法,如下:

should_clear_reference方法判断某个软引用对象是否需要被清理掉,该方法的参数p是指SoftReference对象,而非SoftReference对象保存的软引用对象。setup用来初始化 ReferencePolicy,其类继承关系如下:

其中的NeverClearPolicy和AlwaysClearPolicy的实现很简单,如下:

重点关注另外两个子类的实现。 

2、LRUMaxHeapPolicy / LRUCurrentHeapPolicy

     这两个都是将超过一段时间不使用的SoftReference对象清理掉,区别在于两者计算这“一段时间”的基准,LRUMaxHeapPolicy使用最大的空闲空间的MB数,而LRUCurrentHeapPolicy使用的是当前堆的空闲空间的MB数,即LRUMaxHeapPolicy计算出来的一段时间的值会比LRUCurrentHeapPolicy大。其实现如下:

LRUMaxHeapPolicy::LRUMaxHeapPolicy() {
  setup();
}

void LRUMaxHeapPolicy::setup() {
  size_t max_heap = MaxHeapSize;
  //获取最大剩余空间的MB数
  max_heap -= Universe::get_heap_used_at_last_gc();
  max_heap /= M;
  
  //_max_interval是LRUMaxHeapPolicy定义的一个实例属性
  //SoftRefLRUPolicyMSPerMB表示每MB空闲空间对应的毫秒数,默认值是1000
  _max_interval = max_heap * SoftRefLRUPolicyMSPerMB;
  assert(_max_interval >= 0,"Sanity check");
}


bool LRUMaxHeapPolicy::should_clear_reference(oop p,
                                             jlong timestamp_clock) {
  //timestamp方法返回SoftReference类的timestamp属性,该属性在每次调用get方法获取软引用对象时会被更新成一个由垃圾回收器维护的clock                                
  jlong interval = timestamp_clock - java_lang_ref_SoftReference::timestamp(p);
  assert(interval >= 0, "Sanity check");

  //如果大于_max_interval,返回true,需要被清理
  if(interval <= _max_interval) {
    return false;
  }

  return true;
}

LRUCurrentHeapPolicy::LRUCurrentHeapPolicy() {
  setup();
}


void LRUCurrentHeapPolicy::setup() {
  //逻辑同LRUMaxHeapPolicy,最大的区别是_max_interval的计算逻辑,这里是用当前的剩余空闲空间的MB数
  _max_interval = (Universe::get_heap_free_at_last_gc() / M) * SoftRefLRUPolicyMSPerMB;
  assert(_max_interval >= 0,"Sanity check");
}


bool LRUCurrentHeapPolicy::should_clear_reference(oop p,
                                                  jlong timestamp_clock) {
  jlong interval = timestamp_clock - java_lang_ref_SoftReference::timestamp(p);
  assert(interval >= 0, "Sanity check");

  if(interval <= _max_interval) {
    return false;
  }

  return true;
}

SoftReference中get方法的实现如下:

clock是一个静态私有属性,但是可以通过JNI修改,如下:

当启用C2编译器时使用LRUMaxHeapPolicy,否则使用LRUCurrentHeapPolicy,参考下面ReferenceProcessor::init_statics()方法的实现。

二、DiscoveredList

     DiscoveredList表示处于Pending状态的通过Reference类的discovered属性构成的一个Reference链表,其定义在同目录下的referenceProcessor.hpp中,比较简单,如下:

其中_oop_head是没有开启UseCompressedOops时的链表头,_compressed_head是开启UseCompressedOops时的链表头,_len表示整个链表的长度。

三、DiscoveredListIterator

     DiscoveredListIterator表示DiscoveredList的迭代器,同样位于referenceProcessor.hpp中,用来遍历链表中的Reference实例,其定义的属性如下:

  •   DiscoveredList&    _refs_list;  //关联的DiscoveredList
  •   HeapWord*          _prev_next; // 前一个遍历的Reference实例的discovered属性的地址
  •   oop                _prev; //前一个遍历的Reference实例
  •   oop                _ref; //当前遍历的Reference实例
  •   HeapWord*          _discovered_addr; //当前遍历的Reference实例的discovered属性的地址
  •   oop                _next; //当前遍历的Reference实例的discovered属性的值,即下一个遍历的Reference实例
  •   HeapWord*          _referent_addr; //当前遍历的Reference实例的referent属性的地址
  •   oop                _referent; // 当前遍历的Reference实例的referent属性的值
  •   OopClosure*        _keep_alive; ///将当前_referent对应的oop标记成存活的
  •   BoolObjectClosure* _is_alive; //判断当前_referent对应的oop是否是存活的

重点关注以下遍历DiscoveredList相关方法的实现,其中load_ptrs负责获取当前_ref属性对应的Reference实例的discovered属性及referent属性的地址和值,next方法在load_ptrs方法之后调用,负责切换到下一个遍历元素,如果_ref等于_next则表示已经遍历到链表最后一个元素,remove方法用于将当前Reference实例从链表中移除,具体如下:

inline DiscoveredListIterator(DiscoveredList&    refs_list,
                                OopClosure*        keep_alive,
                                BoolObjectClosure* is_alive):
    _refs_list(refs_list),
    _prev_next(refs_list.adr_head()),
    _prev(NULL),
    _ref(refs_list.head()),
    _next(NULL),
    _keep_alive(keep_alive),
    _is_alive(is_alive)
{ }

void DiscoveredListIterator::load_ptrs(DEBUG_ONLY(bool allow_null_referent)) {
  //获取_ref对应的Reference实例的discovered属性的地址
  _discovered_addr = java_lang_ref_Reference::discovered_addr(_ref);
  //获取_ref对应的Reference实例的discovered属性的值,即链表中下一个Reference实例
  oop discovered = java_lang_ref_Reference::discovered(_ref);
  //要求discovered是oop或者null
  assert(_discovered_addr && discovered->is_oop_or_null(),
         "discovered field is bad");
  _next = discovered;
  //获取_ref对应的Reference实例的referent属性的地址
  _referent_addr = java_lang_ref_Reference::referent_addr(_ref);
   //获取_ref对应的Reference实例的referent属性的值
  _referent = java_lang_ref_Reference::referent(_ref);
  //校验_referent位于Java堆内存中
  assert(Universe::heap()->is_in_reserved_or_null(_referent),
         "Wrong oop found in java.lang.Reference object");
  assert(allow_null_referent ?
             _referent->is_oop_or_null()
           : _referent->is_oop(),
         "bad referent");
}

inline void next() {
    _prev_next = _discovered_addr;
    _prev = _ref;
    move_to_next();
  }

inline void move_to_next() {
    if (_ref == _next) {
      // End of the list.
      _ref = NULL;
    } else {
      _ref = _next;
    }
    assert(_ref != _first_seen, "cyclic ref_list found");
    NOT_PRODUCT(_processed++);
  }

 static HeapWord* discovered_addr(oop ref) {
    return ref->obj_field_addr<HeapWord>(discovered_offset);
  }

 static oop discovered(oop ref) {
    return ref->obj_field(discovered_offset);
  }

 static HeapWord* referent_addr(oop ref) {
    return ref->obj_field_addr<HeapWord>(referent_offset);
  }

static oop referent(oop ref) {
    return ref->obj_field(referent_offset);
  }

这三个方法的调用链是基本一致的,如下:

四、ReferenceProcessor

1、定义

     ReferenceProcessor类封装了java.lang.Reference实例的GC预处理逻辑,对采用分代内存,且各代内存区独立垃圾回收的堆内存尤其有用,其定义同样在referenceProcessor.hpp中,包含如下属性:

  • static bool _pending_list_uses_discovered_field; //与老版的JDK兼容,初始值是false
  • static jlong _soft_ref_timestamp_clock; //SoftReference类的clock属性,初始值是0
  • MemRegion   _span; //查找Reference实例的内存区域
  • bool        _discovering_refs;  //true表示允许查找Reference实例
  • bool        _discovery_is_atomic; //true表示查找动作是原子更新的
  • bool        _discovery_is_mt;  //true表示查找动作是并行的,mt是multi的简写
  • bool        _enqueuing_is_done;  //true表示所有的Reference实例都已经加入到ReferenceQueue中
  • bool        _processing_is_mt;  //true表示Reference实例处理过程是并行的
  • uint        _next_id;  //并行处理Reference实例时用来分发任务的
  • BoolObjectClosure* _is_alive_non_header;  // 用来确定对象的可达性从而判断对象是否存活,适用于那些不把对象是否存活的信息写入对象头的垃圾回收器
  • static ReferencePolicy*   _default_soft_ref_policy; //默认的软引用的清除策略
  • static ReferencePolicy*   _always_clear_soft_ref_policy; //总是清除软引用的策略
  • ReferencePolicy*          _current_soft_ref_policy; //当前使用的策略,是上面描述的两个策略中的一个
  • uint             _num_q; //表示并行处理的线程数量,最低是1,取值通常是ParallelGCThreads
  • uint             _max_num_q; //表示最大的并行线程数,取并行查找和并行处理的线程数的最大值,前者通常是取ConcGCThreads和ParallelGCThreads的最大值,即_max_num_q肯定大于等于_num_q
  • DiscoveredList* _discovered_refs; //实际保存不同类型的Reference子类的DiscoveredList指针的数组
  • DiscoveredList* _discoveredSoftRefs; //下面5个是不同类型的Reference子类实例对应的链表,按照顺序依次对应_discovered_refs中_max_num_q个元素
  • DiscoveredList* _discoveredWeakRefs;
  • DiscoveredList* _discoveredFinalRefs;
  • DiscoveredList* _discoveredPhantomRefs;
  • DiscoveredList* _discoveredCleanerRefs;

重点关注以下方法的实现

2、referenceProcessor_init / 构造方法

     referenceProcessor_init方法用于初始化所有的静态属性,构造方法则初始化所有的实例属性,其实现如下:


void referenceProcessor_init() {
  ReferenceProcessor::init_statics();
}

void ReferenceProcessor::init_statics() {
  //更新_soft_ref_timestamp_clock和SoftReference的clock属性
  jlong now = os::javaTimeNanos() / NANOSECS_PER_MILLISEC;
  _soft_ref_timestamp_clock = now;
  java_lang_ref_SoftReference::set_clock(_soft_ref_timestamp_clock);

  //初始化清除策略
  _always_clear_soft_ref_policy = new AlwaysClearPolicy();
  _default_soft_ref_policy      = new COMPILER2_PRESENT(LRUMaxHeapPolicy())
                                      NOT_COMPILER2(LRUCurrentHeapPolicy());
  if (_always_clear_soft_ref_policy == NULL || _default_soft_ref_policy == NULL) {
    vm_exit_during_initialization("Could not allocate reference policy object");
  }
  guarantee(RefDiscoveryPolicy == ReferenceBasedDiscovery ||
            RefDiscoveryPolicy == ReferentBasedDiscovery,
            "Unrecongnized RefDiscoveryPolicy");
  //初始化_pending_list_uses_discovered_field属性,JDK8下为true
  _pending_list_uses_discovered_field = JDK_Version::current().pending_list_uses_discovered_field();
}

ReferenceProcessor::ReferenceProcessor(MemRegion span,
                                       bool      mt_processing,
                                       uint      mt_processing_degree,
                                       bool      mt_discovery,
                                       uint      mt_discovery_degree,
                                       bool      atomic_discovery,
                                       BoolObjectClosure* is_alive_non_header)  :
  _discovering_refs(false),
  _enqueuing_is_done(false),
  _is_alive_non_header(is_alive_non_header),
  _processing_is_mt(mt_processing),
  _next_id(0)
{
  _span = span;
  _discovery_is_atomic = atomic_discovery;
  _discovery_is_mt     = mt_discovery;
  _num_q               = MAX2(1U, mt_processing_degree);
  _max_num_q           = MAX2(_num_q, mt_discovery_degree);
  //创建一个新的数组
  _discovered_refs     = NEW_C_HEAP_ARRAY(DiscoveredList,
            _max_num_q * number_of_subclasses_of_ref(), mtGC);

  if (_discovered_refs == NULL) {
    //数组创建失败,抛出异常
    vm_exit_during_initialization("Could not allocated RefProc Array");
  }
  //每个子类都对应_discovered_refs中_max_num_q个元素
  _discoveredSoftRefs    = &_discovered_refs[0];
  _discoveredWeakRefs    = &_discoveredSoftRefs[_max_num_q];
  _discoveredFinalRefs   = &_discoveredWeakRefs[_max_num_q];
  _discoveredPhantomRefs = &_discoveredFinalRefs[_max_num_q];
  _discoveredCleanerRefs = &_discoveredPhantomRefs[_max_num_q];

  //将所有数组元素初始化
  for (uint i = 0; i < _max_num_q * number_of_subclasses_of_ref(); i++) {
    _discovered_refs[i].set_head(NULL);
    _discovered_refs[i].set_length(0);
  }

  setup_policy(false /* default soft ref policy */);
}

//获取Reference子类的个数
static int number_of_subclasses_of_ref() { return (REF_CLEANER - REF_OTHER); }

ReferencePolicy* setup_policy(bool always_clear) {
    _current_soft_ref_policy = always_clear ?
      _always_clear_soft_ref_policy : _default_soft_ref_policy;
    _current_soft_ref_policy->setup();   // snapshot the policy threshold
    return _current_soft_ref_policy;
  }

上面方法涉及一个描述java/lang/ref/Reference及其子类类型的枚举ReferenceType的定义如下:

3、discover_reference

     discover_reference方法用于将某个Reference实例加入到对应Reference子类类型的DiscoveredList上,该方法的实现如下:

bool ReferenceProcessor::discover_reference(oop obj, ReferenceType rt) {
  //确保当前允许执行Reference查找,RegisterReferences表示是否允许JVM注册Reference子类实例,是develop属性,默认为true
  //_discovering_refs默认为false,可通过enable_discovery方法将其设置为true
  if (!_discovering_refs || !RegisterReferences) {
    return false;
  }
 
  //获取Reference实例的next属性,当处于Active状态时,next属性为空,只处理Active状态的ce实例
  oop next = java_lang_ref_Reference::next(obj);
  if (next != NULL) {   
    return false;
  }

  HeapWord* obj_addr = (HeapWord*)obj;
  //RefDiscoveryPolicy表示查找Reference实例的策略,默认是0,即ReferenceBasedDiscovery,基于Reference实例的查找策略
  if (RefDiscoveryPolicy == ReferenceBasedDiscovery &&
      !_span.contains(obj_addr)) {
    //关联的span内存区中没有该实例
    return false;
  }

  //只查找哪些没有强引用的对象
  if (is_alive_non_header() != NULL) {
    verify_referent(obj);
    if (is_alive_non_header()->do_object_b(java_lang_ref_Reference::referent(obj))) {
      return false;  //如果对象还是存活的,即还有其他的强引用
    }
  }
  if (rt == REF_SOFT) {
    //如果是软引用,则通过清除策略判断其是否应该清除,如果不需要则返回false
    if (!_current_soft_ref_policy->should_clear_reference(obj, _soft_ref_timestamp_clock)) {
      return false;
    }
  }

  ResourceMark rm;      // Needed for tracing.
  
  //获取discovered属性的地址和值
  HeapWord* const discovered_addr = java_lang_ref_Reference::discovered_addr(obj);
  const oop  discovered = java_lang_ref_Reference::discovered(obj);
  assert(discovered->is_oop_or_null(), "bad discovered field");
  if (discovered != NULL) {
    //discovered属性不为空,说明该实例之前已经查找过了
    if (TraceReferenceGC) {
      gclog_or_tty->print_cr("Already discovered reference (" INTPTR_FORMAT ": %s)",
                             (void *)obj, obj->klass()->internal_name());
    }

    if (RefDiscoveryPolicy == ReferentBasedDiscovery) {
      //如果是基于Referent的策略,为了避免被二次处理则返回false
      return false;
    } else {
      assert(RefDiscoveryPolicy == ReferenceBasedDiscovery,
             "Unrecognized policy");
      // 并行垃圾收集器下可能对同一个Reference实例查找两次
      assert(UseConcMarkSweepGC || UseG1GC,
             "Only possible with a concurrent marking collector");
      return true;
    }
  }

  //如果discovered属性为空
  if (RefDiscoveryPolicy == ReferentBasedDiscovery) {
    verify_referent(obj);
    //必须满足obj和referent对象都在span区域内
    if (_span.contains(obj_addr) ||
        (discovery_is_atomic() &&
         _span.contains(java_lang_ref_Reference::referent(obj)))) {
      // should_enqueue = true;
    } else {
      return false;
    }
  } else {
    assert(RefDiscoveryPolicy == ReferenceBasedDiscovery &&
           _span.contains(obj_addr), "code inconsistency");
  }

  //获取对应ReferenceType的DiscoveredList
  DiscoveredList* list = get_discovered_list(rt);
  if (list == NULL) {
    return false;   // nothing special needs to be done
  }

  if (_discovery_is_mt) {
    //如果并行查找,处理逻辑同下面的单线程查找,不过是增加了原子的修改discovered属性的逻辑
    add_to_discovered_list_mt(*list, obj, discovered_addr);
  } else {
    //单线程查找,将新的Reference实例插入到链表的头部
    oop current_head = list->head();
    //如果current_head为NULL,则当前元素是链表的第一个元素也是遍历时链表的最后一个元素,discovered属性指向它自己
    oop next_discovered = (current_head != NULL) ? current_head : obj;

    assert(discovered == NULL, "control point invariant");
    //修改discovered属性
    oop_store_raw(discovered_addr, next_discovered);
    //重置链表头,链表长度加1
    list->set_head(obj);
    list->inc_length(1);

    if (TraceReferenceGC) {
      gclog_or_tty->print_cr("Discovered reference (" INTPTR_FORMAT ": %s)",
                                (void *)obj, obj->klass()->internal_name());
    }
  }
  assert(obj->is_oop(), "Discovered a bad reference");
  verify_referent(obj);
  return true;
}

void ReferenceProcessor::enable_discovery(bool verify_disabled, bool check_no_refs) {

  //可能有人通过反射或者UnSafe类改写了clock静态属性,这里将其赋值给_soft_ref_timestamp_clock,使用新值来查找
  _soft_ref_timestamp_clock = java_lang_ref_SoftReference::clock();
  _discovering_refs = true;
}

BoolObjectClosure* is_alive_non_header() {
    return _is_alive_non_header;
  }

#ifndef PRODUCT
// Non-atomic 非原子的即并发情形下,referent可能被置为null,生产环境下为空实现
void ReferenceProcessor::verify_referent(oop obj) {
  bool da = discovery_is_atomic();
  //获取referent属性对应的对象
  oop referent = java_lang_ref_Reference::referent(obj);
  assert(da ? referent->is_oop() : referent->is_oop_or_null(),
         err_msg("Bad referent " INTPTR_FORMAT " found in Reference "
                 INTPTR_FORMAT " during %satomic discovery ",
                 (void *)referent, (void *)obj, da ? "" : "non-"));
}
#endif

inline DiscoveredList* ReferenceProcessor::get_discovered_list(ReferenceType rt) {
  uint id = 0;
  // Determine the queue index to use for this object.
  if (_discovery_is_mt) {
    //如果是并行查找,则使用线程ID
    Thread* thr = Thread::current();
    id = thr->as_Worker_thread()->id();
  } else {
    //单线程查找
    if (_processing_is_mt) {
      //如果是并行处理
      id = next_id();
    }
  }
  assert(0 <= id && id < _max_num_q, "Id is out-of-bounds (call Freud?)");

  //根据rt的类型获取对应的DiscoveredList
  DiscoveredList* list = NULL;
  switch (rt) {
    case REF_OTHER:
      // Unknown reference type, no special treatment
      break;
    case REF_SOFT:
      list = &_discoveredSoftRefs[id];
      break;
    case REF_WEAK:
      list = &_discoveredWeakRefs[id];
      break;
    case REF_FINAL:
      list = &_discoveredFinalRefs[id];
      break;
    case REF_PHANTOM:
      list = &_discoveredPhantomRefs[id];
      break;
    case REF_CLEANER:
      list = &_discoveredCleanerRefs[id];
      break;
    case REF_NONE:
      // we should not reach here if we are an InstanceRefKlass
    default:
      ShouldNotReachHere();
  }
  if (TraceReferenceGC && PrintGCDetails) {
    gclog_or_tty->print_cr("Thread %d gets list " INTPTR_FORMAT, id, list);
  }
  return list;
}

 uint next_id() {
    uint id = _next_id;
    //自增后等于_num_q则置为0
    if (++_next_id == _num_q) {
      _next_id = 0;
    }
    return id;
  }

inline void
ReferenceProcessor::add_to_discovered_list_mt(DiscoveredList& refs_list,
                                              oop             obj,
                                              HeapWord*       discovered_addr) {
  assert(_discovery_is_mt, "!_discovery_is_mt should have been handled by caller");
  oop current_head = refs_list.head();
  oop next_discovered = (current_head != NULL) ? current_head : obj;
  //原子的修改discovered属性的值
  oop retest = oopDesc::atomic_compare_exchange_oop(next_discovered, discovered_addr,
                                                    NULL);
  if (retest == NULL) {
    //discovered属性修改成功,重置链表头,增加链表长度
    refs_list.set_head(obj);
    refs_list.inc_length(1);

    if (TraceReferenceGC) {
      gclog_or_tty->print_cr("Discovered reference (mt) (" INTPTR_FORMAT ": %s)",
                             (void *)obj, obj->klass()->internal_name());
    }
  } else {
    //discovered属性修改失败,说明其他线程修改了该
    if (TraceReferenceGC) {
      gclog_or_tty->print_cr("Already discovered reference (" INTPTR_FORMAT ": %s)",
                             (void *)obj, obj->klass()->internal_name());
    }
  }
}

该方法的调用链如下:

从调用链可知在对象遍历的时候如果发现对象是Reference及其子类实例则调用此方法判断是否需要将其加入到对应Reference子类类型的DiscoveredList上,如果需要则加入,并修改当前Reference实例的discovered属性,将其指向DiscoveredList的链表头,如果链表头为null则将其指向自己。注意上述方法并未修改关键的Reference的静态属性pending。

4、enqueue_discovered_references

      enqueue_discovered_references用于将各个DiscoveredList中包含的Reference实例加入到由静态属性pending和实例属性discovered构成的一个链表中并更新静态pending属性指向最新的链表头,更新Reference实例的next属性指向它自己,即将Reference实例标记成Pending状态,处理完成后再将DiscoveredList恢复成初始状态,其实现如下:

bool ReferenceProcessor::enqueue_discovered_references(AbstractRefProcTaskExecutor* task_executor) {
  NOT_PRODUCT(verify_ok_to_handle_reflists());
  if (UseCompressedOops) {
    return enqueue_discovered_ref_helper<narrowOop>(this, task_executor);
  } else {
    return enqueue_discovered_ref_helper<oop>(this, task_executor);
  }
}

template <class T>
bool enqueue_discovered_ref_helper(ReferenceProcessor* ref,
                                   AbstractRefProcTaskExecutor* task_executor) {

  //获取静态pending属性的地址
  T* pending_list_addr = (T*)java_lang_ref_Reference::pending_list_addr();
  //获取原来的pending属性的值
  T old_pending_list_value = *pending_list_addr;

  // Enqueue references that are not made active again, and
  // clear the decks for the next collection (cycle).
  ref->enqueue_discovered_reflists((HeapWord*)pending_list_addr, task_executor);
  // 更新bs
  oopDesc::bs()->write_ref_field(pending_list_addr, oopDesc::load_decode_heap_oop(pending_list_addr));

  //暂停Reference实例查找
  ref->disable_discovery();

  //如果有新的Reference实例加入到链表中则pending属性会更新,返回true
  return old_pending_list_value != *pending_list_addr;
}

HeapWord *java_lang_ref_Reference::pending_list_addr() {
  InstanceKlass* ik = InstanceKlass::cast(SystemDictionary::Reference_klass());
  address addr = ik->static_field_addr(static_pending_offset);
  // XXX This might not be HeapWord aligned, almost rather be char *.
  return (HeapWord*)addr;
}

void ReferenceProcessor::enqueue_discovered_reflists(HeapWord* pending_list_addr,
  AbstractRefProcTaskExecutor* task_executor) {
  //如果并行处理
  if (_processing_is_mt && task_executor != NULL) {
    // Parallel code
    RefProcEnqueueTask tsk(*this, _discovered_refs,
                           pending_list_addr, _max_num_q);
    task_executor->execute(tsk);
  } else {
    //单线程处理
    for (uint i = 0; i < _max_num_q * number_of_subclasses_of_ref(); i++) {
      //将DiscoveredList中的所有Reference实例加入到通过pending属性和discovered属性构成的一个链表中
      enqueue_discovered_reflist(_discovered_refs[i], pending_list_addr);
      //处理完成将DiscoveredList恢复成初始状态
      _discovered_refs[i].set_head(NULL);
      _discovered_refs[i].set_length(0);
    }
  }
}

void ReferenceProcessor::enqueue_discovered_reflist(DiscoveredList& refs_list,
                                                    HeapWord* pending_list_addr) {

  if (TraceReferenceGC && PrintGCDetails) {
    gclog_or_tty->print_cr("ReferenceProcessor::enqueue_discovered_reflist list "
                           INTPTR_FORMAT, (address)refs_list.head());
  }

  oop obj = NULL;
  //获取DiscoveredList的头元素
  oop next_d = refs_list.head();
  if (pending_list_uses_discovered_field()) { //JDK8下默认走此分支
    // Walk down the list, self-looping the next field
    // so that the References are not considered active.
    while (obj != next_d) {

      obj = next_d;
      assert(obj->is_instanceRef(), "should be reference object");
      //获取链表中下一个实例
      next_d = java_lang_ref_Reference::discovered(obj);
      if (TraceReferenceGC && PrintGCDetails) {
        gclog_or_tty->print_cr("        obj " INTPTR_FORMAT "/next_d " INTPTR_FORMAT,
                               (void *)obj, (void *)next_d);
      }
      assert(java_lang_ref_Reference::next(obj) == NULL,
             "Reference not active; should not be discovered");
      //将next属性指向它自己,从而标记Reference实例状态不是Active
      java_lang_ref_Reference::set_next_raw(obj, obj);
      if (next_d != obj) {
        //更新bs
        oopDesc::bs()->write_ref_field(java_lang_ref_Reference::discovered_addr(obj), next_d);
      } else {
        //如果是DiscoveredList链表最后一个元素
        //将链表头元素写入pending属性
        oop old = oopDesc::atomic_exchange_oop(refs_list.head(), pending_list_addr);
        //将pending属性原来的值,可能是null,写入到obj的next属性中,因为该值不在DiscoveredList链表中
        //通过此操作将不同的DiscoveredList中的Reference实例插入到一个链表中
        java_lang_ref_Reference::set_discovered_raw(obj, old); // old may be NULL
        //更新bs
        oopDesc::bs()->write_ref_field(java_lang_ref_Reference::discovered_addr(obj), old);
      }
    }
  } else { // 老版JDK的处理,将discovered属性的值复制到next属性中,然后清空discovered属性
  
    while (obj != next_d) {
      obj = next_d;
      assert(obj->is_instanceRef(), "should be reference object");
      next_d = java_lang_ref_Reference::discovered(obj);
      if (TraceReferenceGC && PrintGCDetails) {
        gclog_or_tty->print_cr("        obj " INTPTR_FORMAT "/next_d " INTPTR_FORMAT,
                               (void *)obj, (void *)next_d);
      }
      assert(java_lang_ref_Reference::next(obj) == NULL,
             "The reference should not be enqueued");
      if (next_d == obj) {  // obj is last
        oop old = oopDesc::atomic_exchange_oop(refs_list.head(), pending_list_addr);
        if (old == NULL) {
          // obj should be made to point to itself, since
          // pending list was empty.
          java_lang_ref_Reference::set_next(obj, obj);
        } else {
          java_lang_ref_Reference::set_next(obj, old);
        }
      } else {
        java_lang_ref_Reference::set_next(obj, next_d);
      }
      java_lang_ref_Reference::set_discovered(obj, (oop) NULL);
    }
  }
}

 并行时通过RefProcEnqueueTask完成上述逻辑,其实现与单线程时一样,如下:

该方法的调用链如下:

注意该方法是在GC结束后由垃圾回收器调用。 

5、balance_all_queues

      balance_all_queues会分别处理各Reference子类所对应的DiscoveredList,将_max_num_q个DiscoveredList中的Reference实例移动并平均到_num_q个DiscoveredList中,因为只有前_num_q个DiscoveredList会被处理,所谓的移动就只是改变链表中起始节点的链接关系而已,其实现如下:


void ReferenceProcessor::balance_all_queues() {
  balance_queues(_discoveredSoftRefs);
  balance_queues(_discoveredWeakRefs);
  balance_queues(_discoveredFinalRefs);
  balance_queues(_discoveredPhantomRefs);
  balance_queues(_discoveredCleanerRefs);
}

//将_max_num_q个DiscoveredList中的Reference实例平均到_num_q个DiscoveredList中
void ReferenceProcessor::balance_queues(DiscoveredList ref_lists[])
{
  size_t total_refs = 0;
  if (TraceReferenceGC && PrintGCDetails) {
    gclog_or_tty->print_cr("\nBalance ref_lists ");
  }
  //遍历所有的DiscoveredList,统计总的链表长度
  for (uint i = 0; i < _max_num_q; ++i) {
    total_refs += ref_lists[i].length();
    if (TraceReferenceGC && PrintGCDetails) {
      gclog_or_tty->print("%d ", ref_lists[i].length());
    }
  }
  if (TraceReferenceGC && PrintGCDetails) {
    gclog_or_tty->print_cr(" = %d", total_refs);
  }

  //计算平均到_num_q个DiscoveredList时的队列长度
  size_t avg_refs = total_refs / _num_q + 1;
  uint to_idx = 0;
  for (uint from_idx = 0; from_idx < _max_num_q; from_idx++) {
    bool move_all = false;
    if (from_idx >= _num_q) {
      //索引大于_num_q的DiscoveredList中的Reference实例都需要被移动
      move_all = ref_lists[from_idx].length() > 0;
    }
    //DiscoveredList中的Reference实例个数大于平均值,或者需要全部移动
    //会不断移动from_idx的DiscoveredList的Reference实例,直到个数等于平均值,如果是全部移动则直到等于0
    while ((ref_lists[from_idx].length() > avg_refs) ||
           move_all) {
      assert(to_idx < _num_q, "Sanity Check!");
      //如果to_idx处的/DiscoveredList中的Reference实例个数小于平均值
      if (ref_lists[to_idx].length() < avg_refs) {
        size_t refs_to_move;
        //计算需要移动的Reference实例个数
        if (move_all) {
          refs_to_move = MIN2(ref_lists[from_idx].length(),
                              avg_refs - ref_lists[to_idx].length());
        } else {
          refs_to_move = MIN2(ref_lists[from_idx].length() - avg_refs,
                              avg_refs - ref_lists[to_idx].length());
        }
        assert(refs_to_move > 0, "otherwise the code below will fail");

        oop move_head = ref_lists[from_idx].head();
        oop move_tail = move_head;
        oop new_head  = move_head;
        //往后遍历refs_to_move个Reference实例,找到最后一个需要移动的Reference实例
        for (size_t j = 0; j < refs_to_move; ++j) {
          move_tail = new_head;
          new_head = java_lang_ref_Reference::discovered(new_head);
        }

        //将需要移除的多个Reference实例插入到目标to_index处的DiscoveredList中
        if (ref_lists[to_idx].head() == NULL) {
          //如果to_idx处的DiscoveredList是一个空队列,move_tail就是最后一个元素,discovered属性指向它自己
          java_lang_ref_Reference::set_discovered_raw(move_tail, move_tail);
        } else {
          //如果to_idx处的DiscoveredList是一个空队列,则将move_tail的discovered属性指向原来的head元素
          java_lang_ref_Reference::set_discovered_raw(move_tail, ref_lists[to_idx].head());
        }
        //重置对象头和队列长度
        ref_lists[to_idx].set_head(move_head);
        ref_lists[to_idx].inc_length(refs_to_move);

        //将需要移除的多个Reference实例从原来的DiscoveredList中移除
        if (move_tail == new_head) {
          //说明原DiscoveredList中的所有元素都被移除了,将head置为NULL
          ref_lists[from_idx].set_head(NULL);
        } else {
          //重置新head
          ref_lists[from_idx].set_head(new_head);
        }
        //将原DiscoveredList的长度减少
        ref_lists[from_idx].dec_length(refs_to_move);
        if (ref_lists[from_idx].length() == 0) {
          //碰到一个等于0的,说明该DiscoveredList的索引大于_num_q,终止move_all为true时的循环,注意此时跳出的是while循环而非for循环
          break;
        }
      } else {
        //这里是取余,所以实际效果相当于将to_index加1
        to_idx = (to_idx + 1) % _num_q;
      }
    }
  }

}

其调用链如下:

发布了117 篇原创文章 · 获赞 8 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_31865983/article/details/103976994