目录
2、LRUMaxHeapPolicy / LRUCurrentHeapPolicy
2、referenceProcessor_init / 构造方法
4、enqueue_discovered_references
本篇博客开始讲解用于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;
}
}
}
}
其调用链如下: