/* When active: NULL * pending: this * Enqueued: next reference in queue (or this if last) * Inactive: this */ @SuppressWarnings("rawtypes") volatile Reference next;
/* 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 */ privatetransient Reference<T> discovered;
lock: 线程安全的锁
1 2 3 4 5 6 7
/* Object used to synchronize with the garbage collector. The collector * must acquire this lock at the beginning of each collection cycle. It is * therefore critical that any code holding this lock complete as quickly * as possible, allocate no new objects, and avoid calling user code. */ staticprivateclassLock { } privatestaticLocklock=newLock();
/* List of References waiting to be enqueued. The collector adds * 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;
/** * Returns this reference object's referent. If this reference object has * been cleared, either by the program or by the garbage collector, then * this method returns <code>null</code>. * * @return The object to which this reference refers, or * <code>null</code> if this reference object has been cleared */ // 获取referent实例 @HotSpotIntrinsicCandidate public T get() { returnthis.referent; }
/** * Clears this reference object. Invoking this method will not cause this * object to be enqueued. * * <p> This method is invoked only by Java code; when the garbage collector * clears references it does so directly, without invoking this method. */ // 清除referent实例 publicvoidclear() { this.referent = null; }
/* -- Queue operations -- */
/** * Tells whether or not this reference object has been enqueued, either by * the program or by the garbage collector. If this reference object was * not registered with a queue when it was created, then this method will * always return <code>false</code>. * * @return <code>true</code> if and only if this reference object has * been enqueued */ // 判断引用队列是否处于ENQUEUED状态 publicbooleanisEnqueued() { return (this.queue == ReferenceQueue.ENQUEUED); }
/** * Adds this reference object to the queue with which it is registered, * if any. * * <p> This method is invoked only by Java code; when the garbage collector * enqueues references it does so directly, without invoking this method. * * @return <code>true</code> if this reference object was successfully * enqueued; <code>false</code> if it was already enqueued or if * it was not registered with a queue when it was created */ // 入队 publicbooleanenqueue() { returnthis.queue.enqueue(this); }
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); }
static { // 大致意思就是获取当前线程组的上一层线程组,一层层获取上去,直到最高层的线程组,再去创建ReferenceHandler,以保证他被创建在JVM的system线程组中 ThreadGrouptg= Thread.currentThread().getThreadGroup(); for (ThreadGrouptgn= tg; tgn != null; tg = tgn, tgn = tg.getParent()); Threadhandler=newReferenceHandler(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(newJavaLangRefAccess() { @Override publicbooleantryHandlePendingReference() { return tryHandlePending(false); } }); }
/** * Try handle pending {@link Reference} if there is one.<p> * Return {@code true} as a hint that there might be another * {@link Reference} pending or {@code false} when there are no more pending * {@link Reference}s at the moment and the program can do some other * useful work instead of looping. * * @param waitForNotify if {@code true} and there was no pending * {@link Reference}, wait until notified from VM * or interrupted; if {@code false}, return immediately * when there is no pending {@link Reference}. * @return {@code true} if there was a {@link Reference} pending and it * was processed, or we waited for notification and either got it * or thread was interrupted before being notified; * {@code false} otherwise. */ 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... // 判断是不是Cleaner,如果是,后续有特殊处理 c = r instanceof Cleaner ? (Cleaner) r : null; // unlink 'r' from 'pending' chain // 再指向下一个元素,并将当前元素置空,熟悉的链表的处理 pending = r.discovered; r.discovered = null; } else { // 如果pending不为null的话,则证明当前没有元素要被加入到queue了,则挂起当前线程,也就是ReferenceHandler // 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 // 如果是Cleaner,则调用clear进行回收 if (c != null) { c.clean(); returntrue; } // 如果Reference有queue,则加入进去 ReferenceQueue<? super Object> q = r.queue; if (q != ReferenceQueue.NULL) q.enqueue(r); returntrue; }
assert(!enqueuing_is_done(), "If here enqueuing should not be complete"); // Stop treating discovered references specially. disable_discovery();
// If discovery was concurrent, someone could have modified // the value of the static field in the j.l.r.SoftReference // class that holds the soft reference timestamp clock using // reflection or Unsafe between when discovery was enabled and // now. Unconditionally update the static field in ReferenceProcessor // here so that we use the new value during processing of the // discovered soft refs.
// Process cleaners, but include them in phantom statistics. We expect // Cleaner references to be temporary, and don't want to deal with // possible incompatibilities arising from making it more visible. phantom_count += process_discovered_reflist(_discoveredCleanerRefs, NULL, false, is_alive, keep_alive, complete_gc, task_executor); }
// Weak global JNI references. It would make more sense (semantically) to // traverse these simultaneously with the regular weak references above, but // that is not how the JDK1.2 specification is. See #4126360. Native code can // thus use JNI weak references to circumvent the phantom references and // resurrect a "post-mortem" object. { GCTraceTime tt("JNI Weak Reference", trace_time, false, gc_timer, gc_id); if (task_executor != NULL) { task_executor->set_single_threaded_mode(); } process_phaseJNI(is_alive, keep_alive, complete_gc); }
size_t ReferenceProcessor::process_discovered_reflist( DiscoveredList refs_lists[], ReferencePolicy* policy, bool clear_referent, BoolObjectClosure* is_alive, OopClosure* keep_alive, VoidClosure* complete_gc, AbstractRefProcTaskExecutor* task_executor) { bool mt_processing = task_executor != NULL && _processing_is_mt; // If discovery used MT and a dynamic number of GC threads, then // the queues must be balanced for correctness if fewer than the // maximum number of queues were used. The number of queue used // during discovery may be different than the number to be used // for processing so don't depend of _num_q < _max_num_q as part // of the test. bool must_balance = _discovery_is_mt;
if ((mt_processing && ParallelRefProcBalancingEnabled) || must_balance) { balance_queues(refs_lists); }
if (PrintReferenceGC && PrintGCDetails) { gclog_or_tty->print(", %u refs", total_list_count); }
// 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. // 只处理软引用 // 将所有不存活但是还不能被回收的软引用从refs_lists中移除(只有refs_lists为软引用的时候,这里policy才不为null) 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. // 根据clear_referent的值决定是否将不存活对象回收 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); } }
// M = 1024 * 1024 // SoftRefLRUPolicyMSPerMB = 1000
// Capture state (of-the-VM) information needed to evaluate the policy voidLRUCurrentHeapPolicy::setup(){ _max_interval = (Universe::get_heap_free_at_last_gc() / M) * SoftRefLRUPolicyMSPerMB; assert(_max_interval >= 0,"Sanity check"); }
// The oop passed in is the SoftReference object, and not // the object the SoftReference points to. boolLRUCurrentHeapPolicy::should_clear_reference(oop p, jlong timestamp_clock){ jlong interval = timestamp_clock - java_lang_ref_SoftReference::timestamp(p); assert(interval >= 0, "Sanity check");
// The interval will be zero if the ref was accessed since the last scavenge/gc. if(interval <= _max_interval) { returnfalse; }
returntrue; }
// Capture state (of-the-VM) information needed to evaluate the policy voidLRUMaxHeapPolicy::setup(){ size_t max_heap = MaxHeapSize; max_heap -= Universe::get_heap_used_at_last_gc(); max_heap /= M;
// The oop passed in is the SoftReference object, and not // the object the SoftReference points to. boolLRUMaxHeapPolicy::should_clear_reference(oop p, jlong timestamp_clock){ // 此方法和上面的一模一样,所以不再单独拿出来
单纯看他两的setup方法:
1 2
_max_interval = (Universe::get_heap_free_at_last_gc() / M) * SoftRefLRUPolicyMSPerMB; _max_interval = (MaxHeapSize - Universe::get_heap_used_at_last_gc()) / M * SoftRefLRUPolicyMSPerMB;
// Traverse the list and remove any Refs that are not active, or // whose referents are either alive or NULL. void ReferenceProcessor::pp2_work(DiscoveredList& refs_list, BoolObjectClosure* is_alive, OopClosure* keep_alive){ assert(discovery_is_atomic(), "Error"); DiscoveredListIterator iter(refs_list, keep_alive, is_alive); // 遍历refs_list中的所有元素 while (iter.has_next()) { iter.load_ptrs(DEBUG_ONLY(false/* allow_null_referent */)); DEBUG_ONLY(oop next = java_lang_ref_Reference::next(iter.obj());) assert(next == NULL, "Should not discover inactive Reference"); // 判断引用是否存活,存活则从refs_list中移除,否则遍历下一个元素 if (iter.is_referent_alive()) { if (TraceReferenceGC) { gclog_or_tty->print_cr("Dropping strongly reachable reference (" INTPTR_FORMAT ": %s)", (void *)iter.obj(), iter.obj()->klass()->internal_name()); } // The referent is reachable after all. // Remove Reference object from list. iter.remove(); // Update the referent pointer as necessary: Note that this // should not entail any recursive marking because the // referent must already have been traversed. iter.make_referent_alive(); iter.move_to_next(); } else { iter.next(); } } NOT_PRODUCT( if (PrintGCDetails && TraceReferenceGC && (iter.processed() > 0)) { gclog_or_tty->print_cr(" Dropped %d active Refs out of %d " "Refs in discovered list " INTPTR_FORMAT, iter.removed(), iter.processed(), (address)refs_list.head()); } ) }
// 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); // 遍历refs_list,此时这里已经是经过phase1和2过滤后的剩下的元素 while (iter.has_next()) { // 更新discovered变量,discovered的值更新为上一个元素的discovered iter.update_discovered(); iter.load_ptrs(DEBUG_ONLY(false/* allow_null_referent */)); if (clear_referent) { // NULL out referent pointer // 清除引用,之后会被GC回收 iter.clear_referent(); } else { // keep the referent around // 标记引用的对象为存活,该对象在这次GC不会被回收 iter.make_referent_alive(); } if (TraceReferenceGC) { gclog_or_tty->print_cr("Adding %sreference (" INTPTR_FORMAT ": %s) as pending", clear_referent ? "cleared " : "", (void *)iter.obj(), iter.obj()->klass()->internal_name()); } assert(iter.obj()->is_oop(UseConcMarkSweepGC), "Adding a bad reference"); iter.next(); } // Remember to update the next pointer of the last ref. // 更新discovered变量 iter.update_discovered(); // Close the reachable set complete_gc->do_void(); }