publicabstractclassReference<T> { private T referent; // 引用所指向的真实对象 volatile ReferenceQueue<? super T> queue; //引用处理列表 /* When active: next element in a discovered reference list maintained by GC (or this if last) * pending: next element in the pending list (or null if last) * otherwise: NULL */ transientprivate Reference<T> discovered; /* used by VM ,指向pending链表下一个节点 * References to this list, while the Reference-handler thread removes * them. This list is protected by the above lock object. The * list uses the discovered field to link its elements. */ privatestatic Reference<Object> pending = null; //静态的链表头 privatestaticclassReferenceHandlerextendsThread{
privatestaticvoidensureClassInitialized(Class<?> clazz){ try { Class.forName(clazz.getName(), true, clazz.getClassLoader()); } catch (ClassNotFoundException e) { throw (Error) new NoClassDefFoundError(e.getMessage()).initCause(e); } } static { // pre-load and initialize InterruptedException and Cleaner classes // so that we don't get into trouble later in the run loop if there's // memory shortage while loading/initializing them lazily. ensureClassInitialized(InterruptedException.class); ensureClassInitialized(Cleaner.class); }
publicvoidrun(){ while (true) { //死循环执行 tryHandlePending(true); } } } staticbooleantryHandlePending(boolean waitForNotify){ Reference<Object> r; Cleaner c; try { synchronized (lock) { if (pending != null) { r = pending; // 'instanceof' might throw OutOfMemoryError sometimes // so do this before un-linking 'r' from the 'pending' chain... c = r instanceof Cleaner ? (Cleaner) r : null; // unlink 'r' from 'pending' chain pending = r.discovered; r.discovered = null; } else { // The waiting on the lock may cause an OutOfMemoryError // because it may try to allocate exception objects. if (waitForNotify) { lock.wait(); } // retry if waited return waitForNotify; } } } catch (OutOfMemoryError x) { // Give other threads CPU time so they hopefully drop some live references // and GC reclaims some space. // Also prevent CPU intensive spinning in case 'r instanceof Cleaner' above // persistently throws OOME for some time... Thread.yield(); // retry returntrue; } catch (InterruptedException x) { // retry returntrue; }
// Fast path for cleaners if (c != null) { c.clean(); returntrue; }
ReferenceQueue<? super Object> q = r.queue; if (q != ReferenceQueue.NULL) q.enqueue(r); returntrue; }
//类加载完就起好最高优先级的ReferenceHandler static { ThreadGroup tg = Thread.currentThread().getThreadGroup(); for (ThreadGroup tgn = tg; tgn != null; tg = tgn, tgn = tg.getParent()); Thread handler = new ReferenceHandler(tg, "Reference Handler"); /* If there were a special system-only priority greater than * MAX_PRIORITY, it would be used here */ handler.setPriority(Thread.MAX_PRIORITY); handler.setDaemon(true); handler.start();
// provide access in SharedSecrets SharedSecrets.setJavaLangRefAccess(new JavaLangRefAccess() { @Override publicbooleantryHandlePendingReference(){ return tryHandlePending(false); } }); } // ... }
privatestaticclassEntry<K,V> extendsWeakReference<Object> implementsMap.Entry<K,V> { V value; finalint hash; Entry<K,V> next;
/** * Creates new entry. */ Entry(Object key, V value, ReferenceQueue<Object> queue, int hash, Entry<K,V> next) { super(key, queue); this.value = value; this.hash = hash; this.next = next; } }
/** * Expunges stale entries from the table. */ privatevoidexpungeStaleEntries(){ for (Object x; (x = queue.poll()) != null; ) { synchronized (queue) { @SuppressWarnings("unchecked") Entry<K,V> e = (Entry<K,V>) x; int i = indexFor(e.hash, table.length);
Entry<K,V> prev = table[i]; Entry<K,V> p = prev; while (p != null) { Entry<K,V> next = p.next; if (p == e) { if (prev == e) table[i] = next; else prev.next = next; // Must not null out e.next; // stale entries may be in use by a HashIterator e.value = null; // Help GC size--; break; } prev = p; p = next; } } } }
gch->gen_process_roots(_gen->level(), true, // Process younger gens, if any, // as strong roots. false, // no scope; this is parallel code GenCollectedHeap::SO_ScavengeCodeCache, GenCollectedHeap::StrongAndWeakRoots, &par_scan_state.to_space_root_closure(), &par_scan_state.older_gen_closure(), &cld_scan_closure);
bool ReferenceProcessor::discover_reference(oop obj, ReferenceType rt) { ... //只收集那些“引用的真实对象暂时还不确定是否被其他强引用的”的引用 // We only discover references whose referents are not (yet) // known to be strongly reachable. if (is_alive_non_header() != NULL) { verify_referent(obj); if (is_alive_non_header()->do_object_b(java_lang_ref_Reference::referent(obj))) { returnfalse; // referent is reachable } } ... //将找到的各种引用加入到收集的引用列表 if (_discovery_is_mt) { add_to_discovered_list_mt(*list, obj, discovered_addr); } else { // We do a raw store here: the field will be visited later when processing // the discovered references. oop current_head = list->head(); // The last ref must have its discovered field pointing to itself. oop next_discovered = (current_head != NULL) ? current_head : obj; assert(discovered == NULL, "control point invariant"); oop_store_raw(discovered_addr, next_discovered); 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()); } // ... }
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 1 (soft refs only): // . Traverse the list and remove any SoftReferences whose // referents are not alive, but that should be kept alive for // policy reasons. Keep alive the transitive closure of all // such referents. if (policy != NULL) { if (mt_processing) { RefProcPhase1Task phase1(*this, refs_lists, policy, true/*marks_oops_alive*/); task_executor->execute(phase1); } else { for (uint i = 0; i < _max_num_q; i++) { process_phase1(refs_lists[i], policy, is_alive, keep_alive, complete_gc); } } } else { // policy == NULL assert(refs_lists != _discoveredSoftRefs, "Policy must be specified for soft references."); } // Phase 2: // . Traverse the list and remove any refs whose referents are alive. if (mt_processing) { RefProcPhase2Task phase2(*this, refs_lists, !discovery_is_atomic()/*marks_oops_alive*/); task_executor->execute(phase2); } else { for (uint i = 0; i < _max_num_q; i++) { process_phase2(refs_lists[i], is_alive, keep_alive, complete_gc); } // Phase 3: // . Traverse the list and process referents as appropriate. if (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); } } // ...
void ReferenceProcessor::enqueue_discovered_reflist(DiscoveredList& refs_list, HeapWord* pending_list_addr) { if (pending_list_uses_discovered_field()) { // New behavior // 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"); // Self-loop next, so as to make Ref not active. java_lang_ref_Reference::set_next_raw(obj, obj); if (next_d != obj) { oopDesc::bs()->write_ref_field(java_lang_ref_Reference::discovered_addr(obj), next_d); } else { // This is the last object. // Swap refs_list into pending_list_addr and // set obj's discovered to what we read from pending_list_addr. oop old = oopDesc::atomic_exchange_oop(refs_list.head(), pending_list_addr); // Need post-barrier on pending_list_addr. See enqueue_discovered_ref_helper() above. java_lang_ref_Reference::set_discovered_raw(obj, old); // old may be NULL oopDesc::bs()->write_ref_field(java_lang_ref_Reference::discovered_addr(obj), old); } //... } // ... }