< prev index next >

src/share/vm/gc/shared/referenceProcessor.cpp

Print this page

        

*** 115,127 **** if (_discovered_refs == NULL) { vm_exit_during_initialization("Could not allocated RefProc Array"); } _discoveredSoftRefs = &_discovered_refs[0]; _discoveredWeakRefs = &_discoveredSoftRefs[_max_num_q]; ! _discoveredFinalRefs = &_discoveredWeakRefs[_max_num_q]; _discoveredPhantomRefs = &_discoveredFinalRefs[_max_num_q]; - _discoveredCleanerRefs = &_discoveredPhantomRefs[_max_num_q]; // Initialize all entries to NULL 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); --- 115,127 ---- if (_discovered_refs == NULL) { vm_exit_during_initialization("Could not allocated RefProc Array"); } _discoveredSoftRefs = &_discovered_refs[0]; _discoveredWeakRefs = &_discoveredSoftRefs[_max_num_q]; ! _discoveredEphemerons = &_discoveredWeakRefs[_max_num_q]; ! _discoveredFinalRefs = &_discoveredEphemerons[_max_num_q]; _discoveredPhantomRefs = &_discoveredFinalRefs[_max_num_q]; // Initialize all entries to NULL 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);
*** 206,240 **** // here so that we use the new value during processing of the // discovered soft refs. _soft_ref_timestamp_clock = java_lang_ref_SoftReference::clock(); - // Include cleaners 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. ReferenceProcessorStats stats( total_count(_discoveredSoftRefs), total_count(_discoveredWeakRefs), total_count(_discoveredFinalRefs), ! total_count(_discoveredPhantomRefs) + total_count(_discoveredCleanerRefs)); // Soft references { GCTraceTime(Debug, gc, ref) tt("SoftReference", gc_timer); process_discovered_reflist(_discoveredSoftRefs, _current_soft_ref_policy, true, is_alive, keep_alive, complete_gc, task_executor); } update_soft_ref_master_clock(); // Weak references { GCTraceTime(Debug, gc, ref) tt("WeakReference", gc_timer); process_discovered_reflist(_discoveredWeakRefs, NULL, true, is_alive, keep_alive, complete_gc, task_executor); } // Final references { GCTraceTime(Debug, gc, ref) tt("FinalReference", gc_timer); process_discovered_reflist(_discoveredFinalRefs, NULL, false, is_alive, keep_alive, complete_gc, task_executor); --- 206,263 ---- // here so that we use the new value during processing of the // discovered soft refs. _soft_ref_timestamp_clock = java_lang_ref_SoftReference::clock(); ReferenceProcessorStats stats( total_count(_discoveredSoftRefs), total_count(_discoveredWeakRefs), + total_count(_discoveredEphemerons), total_count(_discoveredFinalRefs), ! total_count(_discoveredPhantomRefs)); ! ! // Ephemerons (phase2) before Soft references. This closes the hard-reachable ! // set that arrises when the value of an ephemeron with a hard-reachable key ! // refers to an otherwise weaker-than-hard-reachable key of some other ephemeron. ! { ! GCTraceTime(Debug, gc, ref) tt("Ephemeron-HardClosure", gc_timer); ! // balance queues if needed 1st ! balance_discovered_ephemerons(task_executor); ! process_discovered_ephemerons_ph2(is_alive, keep_alive, complete_gc, task_executor); ! } // Soft references { GCTraceTime(Debug, gc, ref) tt("SoftReference", gc_timer); process_discovered_reflist(_discoveredSoftRefs, _current_soft_ref_policy, true, is_alive, keep_alive, complete_gc, task_executor); } update_soft_ref_master_clock(); + // Ephemerons (phase2) again before Weak references. This closes the soft-reachable + // set that arrises when the value of an ephemeron with a soft-reachable key + // refers to an otherwise weaker-than-soft-reachable key of some other ephemeron. + { + GCTraceTime(Debug, gc, ref) tt("Ephemeron-SoftClosure", gc_timer); + process_discovered_ephemerons_ph2(is_alive, keep_alive, complete_gc, task_executor); + } + + // Weak references { GCTraceTime(Debug, gc, ref) tt("WeakReference", gc_timer); process_discovered_reflist(_discoveredWeakRefs, NULL, true, is_alive, keep_alive, complete_gc, task_executor); } + // Ephemerons (phase3). This clears any remaining ephemerons. + { + GCTraceTime(Debug, gc, ref) tt("Ephemeron-Clear", gc_timer); + process_discovered_ephemerons_ph3(is_alive, keep_alive, complete_gc, task_executor); + } + // Final references { GCTraceTime(Debug, gc, ref) tt("FinalReference", gc_timer); process_discovered_reflist(_discoveredFinalRefs, NULL, false, is_alive, keep_alive, complete_gc, task_executor);
*** 243,258 **** // Phantom references { GCTraceTime(Debug, gc, ref) tt("PhantomReference", gc_timer); process_discovered_reflist(_discoveredPhantomRefs, NULL, true, is_alive, keep_alive, complete_gc, task_executor); - - // Process cleaners, but include them in phantom timing. We expect - // Cleaner references to be temporary, and don't want to deal with - // possible incompatibilities arising from making it more visible. - process_discovered_reflist(_discoveredCleanerRefs, NULL, true, - 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 --- 266,275 ----
*** 264,275 **** task_executor->set_single_threaded_mode(); } process_phaseJNI(is_alive, keep_alive, complete_gc); } ! log_debug(gc, ref)("Ref Counts: Soft: " SIZE_FORMAT " Weak: " SIZE_FORMAT " Final: " SIZE_FORMAT " Phantom: " SIZE_FORMAT, ! stats.soft_count(), stats.weak_count(), stats.final_count(), stats.phantom_count()); log_develop_trace(gc, ref)("JNI Weak Reference count: " SIZE_FORMAT, count_jni_refs()); return stats; } --- 281,292 ---- task_executor->set_single_threaded_mode(); } process_phaseJNI(is_alive, keep_alive, complete_gc); } ! log_debug(gc, ref)("Ref Counts: Soft: " SIZE_FORMAT " Weak: " SIZE_FORMAT " Ephemeron: " SIZE_FORMAT " Final: " SIZE_FORMAT " Phantom: " SIZE_FORMAT, ! stats.soft_count(), stats.weak_count(), stats.ephemeron_count(), stats.final_count(), stats.phantom_count()); log_develop_trace(gc, ref)("JNI Weak Reference count: " SIZE_FORMAT, count_jni_refs()); return stats; }
*** 588,603 **** iter.removed(), iter.processed(), p2i(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); --- 605,761 ---- iter.removed(), iter.processed(), p2i(refs_list.head())); } ) } ! bool ! ReferenceProcessor::pp2_ephemerons_work(DiscoveredList& refs_list, ! BoolObjectClosure* is_alive, ! OopClosure* keep_alive, ! VoidClosure* complete_gc) { ! assert(discovery_is_atomic(), "Error"); ! DiscoveredListIterator iter(refs_list, keep_alive, is_alive); ! // Temporary list used to reverse the order of ephemerons at each pass to avoid ! // pathological cases where majority of revived ephemeron values point ! // to ephemeron keys in the list "preceeding" this ephemeron. ! DiscoveredList reversed_list; ! bool ephemerons_removed = false; ! while (iter.has_next()) { ! iter.load_ptrs(DEBUG_ONLY(false /* allow_null_referent */)); ! oop obj = iter.obj(); ! DEBUG_ONLY(oop next = java_lang_ref_Reference::next(obj);) ! assert(next == NULL, "Should not discover inactive Reference"); ! if (iter.is_referent_alive()) { ! log_develop_trace(gc, ref)("Dropping strongly reachable reference (" INTPTR_FORMAT ": %s)", ! p2i(obj), obj->klass()->internal_name()); ! // The referent (key) is reachable after all. ! // Remove Ephemeron object from list. ! iter.remove(); ! // Update the referent (key) pointer as necessary: Note that this ! // should not entail any recursive marking because the ! // referent must already have been traversed. ! iter.make_referent_alive(); ! // Update the value pointer as necessary. ! HeapWord* value_addr = java_lang_ref_Ephemeron::value_addr(obj); ! if (UseCompressedOops) { ! keep_alive->do_oop((narrowOop*) value_addr); ! } else { ! keep_alive->do_oop((oop*) value_addr); ! } ! ephemerons_removed = true; ! // Close the newly reachable set as soon as the value is marked to be alive ! // to increase the chance other ephemeron referents (keys) are revived as ! // we proceed scanning the list. ! complete_gc->do_void(); ! } else { ! // Referent (key) is not alive (yet) so move the ephemeron to a reversed_list ! // to reverse scanning in the next pass. ! iter.remove(); ! HeapWord* discovered_addr = java_lang_ref_Reference::discovered_addr(obj); ! oop current_head = reversed_list.head(); ! // The last ref must have its discovered field pointing to itself. ! oop next_discovered = (current_head != NULL) ? current_head : obj; ! oop_store_raw(discovered_addr, next_discovered); ! reversed_list.set_head(obj); ! reversed_list.inc_length(1); ! } ! iter.move_to_next(); ! } ! assert(refs_list.length() == 0, "Should be empty"); ! // replace the list with reversed list ! refs_list = reversed_list; ! NOT_PRODUCT( ! if (iter.processed() > 0) { ! log_develop_trace(gc, ref)(" Dropped " SIZE_FORMAT " active Ephemerons out of " SIZE_FORMAT ! " Ephemerons in discovered list " INTPTR_FORMAT, ! iter.processed() - refs_list.length(), iter.processed(), ! p2i(refs_list.head())); ! } ! ) ! return ephemerons_removed; ! } ! ! bool ! ReferenceProcessor::pp2_ephemerons_work_concurrent_discovery(DiscoveredList& refs_list, ! BoolObjectClosure* is_alive, ! OopClosure* keep_alive, ! VoidClosure* complete_gc) { ! assert(!discovery_is_atomic(), "Error"); ! DiscoveredListIterator iter(refs_list, keep_alive, is_alive); ! // Temporary list used to reverse the order of ephemerons at each pass to avoid ! // pathological cases where majority of revived ephemeron values point ! // to ephemeron keys in the list "preceeding" this ephemeron. ! DiscoveredList reversed_list; ! bool ephemerons_removed = false; ! while (iter.has_next()) { ! iter.load_ptrs(DEBUG_ONLY(true /* allow_null_referent */)); ! oop obj = iter.obj(); ! HeapWord* next_addr = java_lang_ref_Reference::next_addr(obj); ! oop next = java_lang_ref_Reference::next(obj); ! if ((iter.referent() == NULL || iter.is_referent_alive() || ! next != NULL)) { ! assert(next->is_oop_or_null(), "Expected an oop or NULL for next field at " PTR_FORMAT, p2i(next)); ! // Remove Reference object from list ! iter.remove(); ! // Trace the cohorts ! iter.make_referent_alive(); ! if (UseCompressedOops) { ! keep_alive->do_oop((narrowOop*) next_addr); ! } else { ! keep_alive->do_oop((oop*) next_addr); ! } ! HeapWord* value_addr = java_lang_ref_Ephemeron::value_addr(obj); ! if (UseCompressedOops) { ! keep_alive->do_oop((narrowOop*) value_addr); ! } else { ! keep_alive->do_oop((oop*) value_addr); ! } ! ephemerons_removed = true; ! // Close the newly reachable set as soon as the value is marked to be alive ! // to increase the chance other ephemeron keys are revived as we proceed ! // scanning the list ! complete_gc->do_void(); ! } else { ! // Referent (key) is not alive (yet) so move the ephemeron to a reversed_list ! // to reverse scanning in the next pass. ! iter.remove(); ! HeapWord* discovered_addr = java_lang_ref_Reference::discovered_addr(obj); ! oop current_head = reversed_list.head(); ! // The last ref must have its discovered field pointing to itself. ! oop next_discovered = (current_head != NULL) ? current_head : obj; ! oop_store_raw(discovered_addr, next_discovered); ! reversed_list.set_head(obj); ! reversed_list.inc_length(1); ! } ! iter.move_to_next(); ! } ! assert(refs_list.length() == 0, "Should be empty"); ! // replace the list with reversed list ! refs_list = reversed_list; ! // Now close the newly reachable set at least once after the whole list has ! // been scanned even if there were no ephemerons ! if (!ephemerons_removed) { ! complete_gc->do_void(); ! } ! NOT_PRODUCT( ! if (iter.processed() > 0) { ! log_develop_trace(gc, ref)(" Dropped " SIZE_FORMAT " active Ephemerons out of " SIZE_FORMAT ! " Ephemerons in discovered list " INTPTR_FORMAT, ! iter.processed() - refs_list.length(), iter.processed(), ! p2i(refs_list.head())); ! } ! ) ! return ephemerons_removed; ! } ! ! // Traverse the list and process the referents (and values in case of Ephemerons), ! // by either clearing them or keeping them (and their reachable // closure) alive. void ReferenceProcessor::process_phase3(DiscoveredList& refs_list, bool clear_referent, + bool has_ephemerons, BoolObjectClosure* is_alive, OopClosure* keep_alive, VoidClosure* complete_gc) { ResourceMark rm; DiscoveredListIterator iter(refs_list, keep_alive, is_alive);
*** 608,617 **** --- 766,781 ---- iter.clear_referent(); } else { // keep the referent around iter.make_referent_alive(); } + if (has_ephemerons) { + assert(clear_referent, "Ephemerons should always be cleared"); + HeapWord* value_addr = java_lang_ref_Ephemeron::value_addr(iter.obj()); + // NULL out value pointer + oop_store_raw(value_addr, NULL); + } log_develop_trace(gc, ref)("Adding %sreference (" INTPTR_FORMAT ": %s) as pending", clear_referent ? "cleared " : "", p2i(iter.obj()), iter.obj()->klass()->internal_name()); assert(iter.obj()->is_oop(UseConcMarkSweepGC), "Adding a bad reference"); iter.next(); }
*** 666,710 **** class RefProcPhase2Task: public AbstractRefProcTaskExecutor::ProcessTask { public: RefProcPhase2Task(ReferenceProcessor& ref_processor, DiscoveredList refs_lists[], bool marks_oops_alive) ! : ProcessTask(ref_processor, refs_lists, marks_oops_alive) { } virtual void work(unsigned int i, BoolObjectClosure& is_alive, OopClosure& keep_alive, VoidClosure& complete_gc) { ! _ref_processor.process_phase2(_refs_lists[i], &is_alive, &keep_alive, &complete_gc); } }; class RefProcPhase3Task: public AbstractRefProcTaskExecutor::ProcessTask { public: RefProcPhase3Task(ReferenceProcessor& ref_processor, DiscoveredList refs_lists[], bool clear_referent, bool marks_oops_alive) : ProcessTask(ref_processor, refs_lists, marks_oops_alive), ! _clear_referent(clear_referent) { } virtual void work(unsigned int i, BoolObjectClosure& is_alive, OopClosure& keep_alive, VoidClosure& complete_gc) { // Don't use "refs_list_index" calculated in this way because // balance_queues() has moved the Ref's into the first n queues. // Thread* thr = Thread::current(); // int refs_list_index = ((WorkerThread*)thr)->id(); // _ref_processor.process_phase3(_refs_lists[refs_list_index], _clear_referent, ! _ref_processor.process_phase3(_refs_lists[i], _clear_referent, &is_alive, &keep_alive, &complete_gc); } private: bool _clear_referent; }; #ifndef PRODUCT void ReferenceProcessor::log_reflist_counts(DiscoveredList ref_lists[], size_t total_refs) { if (!log_is_enabled(Trace, gc, ref)) { --- 830,886 ---- class RefProcPhase2Task: public AbstractRefProcTaskExecutor::ProcessTask { public: RefProcPhase2Task(ReferenceProcessor& ref_processor, DiscoveredList refs_lists[], + bool has_ephemerons, bool marks_oops_alive) ! : ProcessTask(ref_processor, refs_lists, marks_oops_alive), ! _has_ephemerons(has_ephemerons), ephemerons_removed(false) { } virtual void work(unsigned int i, BoolObjectClosure& is_alive, OopClosure& keep_alive, VoidClosure& complete_gc) { ! bool r = _ref_processor.process_phase2(_refs_lists[i], _has_ephemerons, &is_alive, &keep_alive, &complete_gc); + if (r) { + ephemerons_removed = true; + } } + private: + bool _has_ephemerons; + public: + bool ephemerons_removed; }; class RefProcPhase3Task: public AbstractRefProcTaskExecutor::ProcessTask { public: RefProcPhase3Task(ReferenceProcessor& ref_processor, DiscoveredList refs_lists[], bool clear_referent, + bool has_ephemerons, bool marks_oops_alive) : ProcessTask(ref_processor, refs_lists, marks_oops_alive), ! _clear_referent(clear_referent), ! _has_ephemerons(has_ephemerons) { } virtual void work(unsigned int i, BoolObjectClosure& is_alive, OopClosure& keep_alive, VoidClosure& complete_gc) { // Don't use "refs_list_index" calculated in this way because // balance_queues() has moved the Ref's into the first n queues. // Thread* thr = Thread::current(); // int refs_list_index = ((WorkerThread*)thr)->id(); // _ref_processor.process_phase3(_refs_lists[refs_list_index], _clear_referent, ! _ref_processor.process_phase3(_refs_lists[i], _clear_referent, _has_ephemerons, &is_alive, &keep_alive, &complete_gc); } private: bool _clear_referent; + bool _has_ephemerons; }; #ifndef PRODUCT void ReferenceProcessor::log_reflist_counts(DiscoveredList ref_lists[], size_t total_refs) { if (!log_is_enabled(Trace, gc, ref)) {
*** 803,815 **** } void ReferenceProcessor::balance_all_queues() { balance_queues(_discoveredSoftRefs); balance_queues(_discoveredWeakRefs); balance_queues(_discoveredFinalRefs); balance_queues(_discoveredPhantomRefs); - balance_queues(_discoveredCleanerRefs); } void ReferenceProcessor::process_discovered_reflist( DiscoveredList refs_lists[], ReferencePolicy* policy, --- 979,991 ---- } void ReferenceProcessor::balance_all_queues() { balance_queues(_discoveredSoftRefs); balance_queues(_discoveredWeakRefs); + balance_queues(_discoveredEphemerons); balance_queues(_discoveredFinalRefs); balance_queues(_discoveredPhantomRefs); } void ReferenceProcessor::process_discovered_reflist( DiscoveredList refs_lists[], ReferencePolicy* policy,
*** 854,879 **** } // 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); } } } --- 1030,1150 ---- } // Phase 2: // . Traverse the list and remove any refs whose referents are alive. if (mt_processing) { ! RefProcPhase2Task phase2(*this, refs_lists, ! false /*has_ephemerons*/, ! !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], ! false /*has_ephemerons*/, ! 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, ! false /*has_ephemerons*/, ! 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, + false /*has_ephemerons*/, + is_alive, keep_alive, complete_gc); + } + } + } + + // Balance ephemerons queues if needed + void ReferenceProcessor::balance_discovered_ephemerons( + 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(_discoveredEphemerons); + } + } + + // Process ephemerons, phase2 + void ReferenceProcessor::process_discovered_ephemerons_ph2( + BoolObjectClosure* is_alive, + OopClosure* keep_alive, + VoidClosure* complete_gc, + AbstractRefProcTaskExecutor* task_executor) { + + // Traverse the _discoveredEphemerons lists and for those ephemerons whose keys + // are alive, remove them from the list, mark their values alive and close the + // reachable set. Iterate until lists become stable while reversing the + // direction of scanning in each pass. + bool mt_processing = task_executor != NULL && _processing_is_mt; + bool ephemerons_removed; + bool forward_scan = true; + do { + if (mt_processing) { + RefProcPhase2Task phase2(*this, _discoveredEphemerons, + true /*has_ephemerons*/, + !discovery_is_atomic() /*marks_oops_alive*/); + task_executor->execute(phase2); + ephemerons_removed = phase2.ephemerons_removed; + } else { + ephemerons_removed = false; + // alternate direction of selecting individual lists for scanning to avoid + // pathological cases where majority of revived ephemeron values point + // to ephemeron keys in "previous" lists... + if (forward_scan) { + for (uint i = 0; i < _max_num_q; i++) { + ephemerons_removed |= process_phase2(_discoveredEphemerons[i], + true /*has_ephemerons*/, + is_alive, keep_alive, complete_gc); + } + } else { + for (uint i = _max_num_q - 1; i < (uint) - 1; i--) { + ephemerons_removed |= process_phase2(_discoveredEphemerons[i], + true /*has_ephemerons*/, + is_alive, keep_alive, complete_gc); + } + } + forward_scan = !forward_scan; + } + } while (ephemerons_removed); + } + + // Process ephemerons, phase3 + void ReferenceProcessor::process_discovered_ephemerons_ph3( + BoolObjectClosure* is_alive, + OopClosure* keep_alive, + VoidClosure* complete_gc, + AbstractRefProcTaskExecutor* task_executor) { + + // Traverse the _discoveredEphemerons lists and clear ephemerons. + bool mt_processing = task_executor != NULL && _processing_is_mt; + if (mt_processing) { + RefProcPhase3Task phase3(*this, _discoveredEphemerons, + true /*clear_referent*/, + true /*has_ephemerons*/, + true /*marks_oops_alive*/); + task_executor->execute(phase3); + } else { + for (uint i = 0; i < _max_num_q; i++) { + process_phase3(_discoveredEphemerons[i], + true /*clear_referent*/, + true /*has_ephemerons*/, is_alive, keep_alive, complete_gc); } } }
*** 904,922 **** 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(); } --- 1175,1193 ---- list = &_discoveredSoftRefs[id]; break; case REF_WEAK: list = &_discoveredWeakRefs[id]; break; + case REF_EPHEMERON: + list = &_discoveredEphemerons[id]; + break; case REF_FINAL: list = &_discoveredFinalRefs[id]; break; case REF_PHANTOM: list = &_discoveredPhantomRefs[id]; break; case REF_NONE: // we should not reach here if we are an InstanceRefKlass default: ShouldNotReachHere(); }
*** 1114,1123 **** --- 1385,1427 ---- OopClosure* keep_alive, VoidClosure* complete_gc, YieldClosure* yield, GCTimer* gc_timer) { + // Ephemerons - iterate until the lists become stable + { + GCTraceTime(Debug, gc, ref) tt("Preclean Ephemerons", gc_timer); + bool ephemerons_removed; + bool forward_scan = true; + do { + ephemerons_removed = false; + // alternate direction of selecting individual lists for scanning to avoid + // pathological cases where majority of revived ephemeron values point + // to ephemeron keys in "previous" lists... + if (forward_scan) { + for (uint i = 0; i < _max_num_q; i++) { + if (yield->should_return()) { + return; + } + ephemerons_removed |= + preclean_discovered_ephemerons_reflist(_discoveredEphemerons[i], is_alive, + keep_alive, complete_gc, yield); + } + } else { + for (uint i = _max_num_q - 1; i < (uint) - 1; i--) { + if (yield->should_return()) { + return; + } + ephemerons_removed |= + preclean_discovered_ephemerons_reflist(_discoveredEphemerons[i], is_alive, + keep_alive, complete_gc, yield); + } + } + forward_scan = !forward_scan; + } while (ephemerons_removed); + } + // Soft references { GCTraceTime(Debug, gc, ref) tm("Preclean SoftReferences", gc_timer); for (uint i = 0; i < _max_num_q; i++) { if (yield->should_return()) {
*** 1160,1180 **** return; } preclean_discovered_reflist(_discoveredPhantomRefs[i], is_alive, keep_alive, complete_gc, yield); } - - // Cleaner references. Included in timing for phantom references. We - // expect Cleaner references to be temporary, and don't want to deal with - // possible incompatibilities arising from making it more visible. - for (uint i = 0; i < _max_num_q; i++) { - if (yield->should_return()) { - return; - } - preclean_discovered_reflist(_discoveredCleanerRefs[i], is_alive, - keep_alive, complete_gc, yield); - } } } // Walk the given discovered ref list, and remove all reference objects // whose referents are still alive, whose referents are NULL or which --- 1464,1473 ----
*** 1225,1246 **** log_develop_trace(gc, ref)(" Dropped " SIZE_FORMAT " Refs out of " SIZE_FORMAT " Refs in discovered list " INTPTR_FORMAT, iter.removed(), iter.processed(), p2i(refs_list.head())); } ) } const char* ReferenceProcessor::list_name(uint i) { assert(i <= _max_num_q * number_of_subclasses_of_ref(), "Out of bounds index"); int j = i / _max_num_q; switch (j) { case 0: return "SoftRef"; case 1: return "WeakRef"; ! case 2: return "FinalRef"; ! case 3: return "PhantomRef"; ! case 4: return "CleanerRef"; } ShouldNotReachHere(); return NULL; } --- 1518,1616 ---- log_develop_trace(gc, ref)(" Dropped " SIZE_FORMAT " Refs out of " SIZE_FORMAT " Refs in discovered list " INTPTR_FORMAT, iter.removed(), iter.processed(), p2i(refs_list.head())); } ) } + // The same as above, but specialized for ephemerons and returns true if any + // ephemerons were removed from ref list. + bool + ReferenceProcessor::preclean_discovered_ephemerons_reflist(DiscoveredList& refs_list, + BoolObjectClosure* is_alive, + OopClosure* keep_alive, + VoidClosure* complete_gc, + YieldClosure* yield) { + DiscoveredListIterator iter(refs_list, keep_alive, is_alive); + // Temporary list used to reverse the order of ephemerons at each pass to avoid + // pathological cases where majority of revived ephemeron values point + // to ephemeron keys in the list "preceeding" this ephemeron. + DiscoveredList reversed_list; + bool ephemerons_removed = false; + while (iter.has_next()) { + iter.load_ptrs(DEBUG_ONLY(true /* allow_null_referent */)); + oop obj = iter.obj(); + oop next = java_lang_ref_Reference::next(obj); + if (iter.referent() == NULL || iter.is_referent_alive() || + next != NULL) { + // The referent has been cleared, or is alive, or the Reference is not + // active; we need to trace and mark its cohort. + log_develop_trace(gc, ref)("Precleaning Ephemeron (" INTPTR_FORMAT ": %s)", + p2i(obj), obj->klass()->internal_name()); + // Remove Reference object from list + iter.remove(); + // Keep alive its cohort. + iter.make_referent_alive(); + if (UseCompressedOops) { + narrowOop* next_addr = (narrowOop*) java_lang_ref_Reference::next_addr(obj); + keep_alive->do_oop(next_addr); + } else { + oop* next_addr = (oop*) java_lang_ref_Reference::next_addr(obj); + keep_alive->do_oop(next_addr); + } + HeapWord* value_addr = java_lang_ref_Ephemeron::value_addr(obj); + if (UseCompressedOops) { + keep_alive->do_oop((narrowOop*) value_addr); + } else { + keep_alive->do_oop((oop*) value_addr); + } + ephemerons_removed = true; + // Close the newly reachable set as soon as the value is marked to be alive + // to increase the chance other ephemeron referents (keys) are revived as + // we proceed scanning the list. + complete_gc->do_void(); + } else { + // Referent (key) is not alive (yet) so move the ephemeron to a reversed_list + // to reverse scanning in the next pass. + iter.remove(); + HeapWord* discovered_addr = java_lang_ref_Reference::discovered_addr(obj); + oop current_head = reversed_list.head(); + // The last ref must have its discovered field pointing to itself. + oop next_discovered = (current_head != NULL) ? current_head : obj; + oop_store_raw(discovered_addr, next_discovered); + reversed_list.set_head(obj); + reversed_list.inc_length(1); + } + iter.move_to_next(); + } + assert(refs_list.length() == 0, "Should be empty"); + // replace the list with reversed list + refs_list = reversed_list; + // Close the reachable set even if no ephemeron was removed from list + if (!ephemerons_removed) { + complete_gc->do_void(); + } + NOT_PRODUCT( + if (iter.processed() > 0) { + log_develop_trace(gc, ref)(" Dropped " SIZE_FORMAT " Ephemerons out of " SIZE_FORMAT + " Ephemerons in discovered list " INTPTR_FORMAT, + iter.processed() - refs_list.length(), iter.processed(), + p2i(refs_list.head())); + } + ) + return ephemerons_removed; + } const char* ReferenceProcessor::list_name(uint i) { assert(i <= _max_num_q * number_of_subclasses_of_ref(), "Out of bounds index"); int j = i / _max_num_q; switch (j) { case 0: return "SoftRef"; case 1: return "WeakRef"; ! case 2: return "Ephemeron"; ! case 3: return "FinalRef"; ! case 4: return "PhantomRef"; } ShouldNotReachHere(); return NULL; }
< prev index next >