< prev index next >

src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp

Print this page
rev 7321 : 8048179: Early reclaim of large objects that are referenced by a few objects
Summary: Push the remembered sets of large objects with few referenced into the dirty card queue at the beginning of the evacuation so that they may end up with zero remembered set entries at the end of the collection, and are potentially reclaimed. Also improve timing measurements of the early reclaim mechanism, and shorten flag names.
Reviewed-by: brutisso, jmasa, dfazunen

*** 2140,2150 **** G1StringDedup::stop(); } } void G1CollectedHeap::clear_humongous_is_live_table() { ! guarantee(G1ReclaimDeadHumongousObjectsAtYoungGC, "Should only be called if true"); _humongous_is_live.clear(); } size_t G1CollectedHeap::conservative_max_heap_alignment() { return HeapRegion::max_region_size(); --- 2140,2150 ---- G1StringDedup::stop(); } } void G1CollectedHeap::clear_humongous_is_live_table() { ! guarantee(G1EagerReclaimHumongousObjects, "Should only be called if true"); _humongous_is_live.clear(); } size_t G1CollectedHeap::conservative_max_heap_alignment() { return HeapRegion::max_region_size();
*** 3674,3726 **** class RegisterHumongousWithInCSetFastTestClosure : public HeapRegionClosure { private: size_t _total_humongous; size_t _candidate_humongous; public: ! RegisterHumongousWithInCSetFastTestClosure() : _total_humongous(0), _candidate_humongous(0) { } virtual bool doHeapRegion(HeapRegion* r) { if (!r->startsHumongous()) { return false; } G1CollectedHeap* g1h = G1CollectedHeap::heap(); uint region_idx = r->hrm_index(); ! bool is_candidate = !g1h->humongous_region_is_always_live(region_idx); ! // Is_candidate already filters out humongous regions with some remembered set. ! // This will not lead to humongous object that we mistakenly keep alive because ! // during young collection the remembered sets will only be added to. if (is_candidate) { g1h->register_humongous_region_with_in_cset_fast_test(region_idx); _candidate_humongous++; } _total_humongous++; return false; } size_t total_humongous() const { return _total_humongous; } size_t candidate_humongous() const { return _candidate_humongous; } }; void G1CollectedHeap::register_humongous_regions_with_in_cset_fast_test() { ! if (!G1ReclaimDeadHumongousObjectsAtYoungGC) { ! g1_policy()->phase_times()->record_fast_reclaim_humongous_stats(0, 0); return; } RegisterHumongousWithInCSetFastTestClosure cl; heap_region_iterate(&cl); ! g1_policy()->phase_times()->record_fast_reclaim_humongous_stats(cl.total_humongous(), cl.candidate_humongous()); _has_humongous_reclaim_candidates = cl.candidate_humongous() > 0; ! if (_has_humongous_reclaim_candidates || G1TraceReclaimDeadHumongousObjectsAtYoungGC) { clear_humongous_is_live_table(); } } void G1CollectedHeap::setup_surviving_young_words() { assert(_surviving_young_words == NULL, "pre-condition"); --- 3674,3769 ---- class RegisterHumongousWithInCSetFastTestClosure : public HeapRegionClosure { private: size_t _total_humongous; size_t _candidate_humongous; + + DirtyCardQueue _dcq; + + bool humongous_region_is_candidate(uint index) { + HeapRegion* region = G1CollectedHeap::heap()->region_at(index); + assert(region->startsHumongous(), "Must start a humongous object"); + HeapRegionRemSet* const rset = region->rem_set(); + bool const allow_stale_refs = G1EagerReclaimHumongousObjectsWithStaleRefs; + return !oop(region->bottom())->is_objArray() && + ((allow_stale_refs && rset->occupancy_less_or_equal_than(G1RSetSparseRegionEntries)) || + (!allow_stale_refs && rset->is_empty())); + } + public: ! RegisterHumongousWithInCSetFastTestClosure() ! : _total_humongous(0), ! _candidate_humongous(0), ! _dcq(&JavaThread::dirty_card_queue_set()) { } virtual bool doHeapRegion(HeapRegion* r) { if (!r->startsHumongous()) { return false; } G1CollectedHeap* g1h = G1CollectedHeap::heap(); uint region_idx = r->hrm_index(); ! bool is_candidate = humongous_region_is_candidate(region_idx); ! // Is_candidate already filters out humongous object with large remembered sets. ! // If we have a humongous object with a few remembered sets, we simply flush these ! // remembered set entries into the DCQS. That will result in automatic ! // re-evaluation of their remembered set entries during the following evacuation ! // phase. if (is_candidate) { + if (!r->rem_set()->is_empty()) { + guarantee(r->rem_set()->occupancy_less_or_equal_than(G1RSetSparseRegionEntries), + "Found a not-small remembered set here. This is inconsistent with previous assumptions."); + G1SATBCardTableLoggingModRefBS* bs = g1h->g1_barrier_set(); + HeapRegionRemSetIterator hrrs(r->rem_set()); + size_t card_index; + while (hrrs.has_next(card_index)) { + jbyte* card_ptr = (jbyte*)bs->byte_for_index(card_index); + if (*card_ptr != CardTableModRefBS::dirty_card_val()) { + *card_ptr = CardTableModRefBS::dirty_card_val(); + _dcq.enqueue(card_ptr); + } + } + r->rem_set()->clear_locked(); + } + assert(r->rem_set()->is_empty(), "At this point any humongous candidate remembered set must be empty."); g1h->register_humongous_region_with_in_cset_fast_test(region_idx); _candidate_humongous++; } _total_humongous++; return false; } size_t total_humongous() const { return _total_humongous; } size_t candidate_humongous() const { return _candidate_humongous; } + + void flush_rem_set_entries() { _dcq.flush(); } }; void G1CollectedHeap::register_humongous_regions_with_in_cset_fast_test() { ! if (!G1EagerReclaimHumongousObjects) { ! g1_policy()->phase_times()->record_fast_reclaim_humongous_stats(0.0, 0, 0); return; } + double time = os::elapsed_counter(); RegisterHumongousWithInCSetFastTestClosure cl; heap_region_iterate(&cl); ! ! time = ((double)(os::elapsed_counter() - time) / os::elapsed_frequency()) * 1000.0; ! g1_policy()->phase_times()->record_fast_reclaim_humongous_stats(time, ! cl.total_humongous(), cl.candidate_humongous()); _has_humongous_reclaim_candidates = cl.candidate_humongous() > 0; ! if (_has_humongous_reclaim_candidates || G1TraceEagerReclaimHumongousObjects) { clear_humongous_is_live_table(); } + + // Finally flush all remembered set entries to re-check into the global DCQS. + cl.flush_rem_set_entries(); } void G1CollectedHeap::setup_surviving_young_words() { assert(_surviving_young_words == NULL, "pre-condition");
*** 6271,6296 **** // nobody has a reference to it. // At the start of collection we flush all refinement logs, and remembered sets // are completely up-to-date wrt to references to the humongous object. // // Other implementation considerations: ! // - never consider object arrays: while they are a valid target, they have not ! // been observed to be used as temporary objects. ! // - they would also pose considerable effort for cleaning up the the remembered ! // sets. ! // While this cleanup is not strictly necessary to be done (or done instantly), ! // given that their occurrence is very low, this saves us this additional ! // complexity. uint region_idx = r->hrm_index(); if (g1h->humongous_is_live(region_idx) || g1h->humongous_region_is_always_live(region_idx)) { ! if (G1TraceReclaimDeadHumongousObjectsAtYoungGC) { ! gclog_or_tty->print_cr("Live humongous %d region %d size "SIZE_FORMAT" with remset "SIZE_FORMAT" code roots "SIZE_FORMAT" is marked %d live-other %d obj array %d", ! r->isHumongous(), region_idx, obj->size()*HeapWordSize, r->rem_set()->occupied(), r->rem_set()->strong_code_roots_list_length(), next_bitmap->isMarked(r->bottom()), g1h->humongous_is_live(region_idx), obj->is_objArray() --- 6314,6337 ---- // nobody has a reference to it. // At the start of collection we flush all refinement logs, and remembered sets // are completely up-to-date wrt to references to the humongous object. // // Other implementation considerations: ! // - never consider object arrays at this time because they would pose ! // considerable effort for cleaning up the the remembered sets. This is ! // required because stale remembered sets might reference locations that ! // are currently allocated into. uint region_idx = r->hrm_index(); if (g1h->humongous_is_live(region_idx) || g1h->humongous_region_is_always_live(region_idx)) { ! if (G1TraceEagerReclaimHumongousObjects) { ! gclog_or_tty->print_cr("Live humongous region %u size "SIZE_FORMAT" start "PTR_FORMAT" length "UINT32_FORMAT" with remset "SIZE_FORMAT" code roots "SIZE_FORMAT" is marked %d live-other %d obj array %d", region_idx, obj->size()*HeapWordSize, + r->bottom(), + r->region_num(), r->rem_set()->occupied(), r->rem_set()->strong_code_roots_list_length(), next_bitmap->isMarked(r->bottom()), g1h->humongous_is_live(region_idx), obj->is_objArray()
*** 6302,6317 **** guarantee(!obj->is_objArray(), err_msg("Eagerly reclaiming object arrays is not supported, but the object "PTR_FORMAT" is.", r->bottom())); ! if (G1TraceReclaimDeadHumongousObjectsAtYoungGC) { ! gclog_or_tty->print_cr("Reclaim humongous region %d size "SIZE_FORMAT" start "PTR_FORMAT" region %d length "UINT32_FORMAT" with remset "SIZE_FORMAT" code roots "SIZE_FORMAT" is marked %d live-other ", ! r->isHumongous(), obj->size()*HeapWordSize, r->bottom(), - region_idx, r->region_num(), r->rem_set()->occupied(), r->rem_set()->strong_code_roots_list_length(), next_bitmap->isMarked(r->bottom()), g1h->humongous_is_live(region_idx), --- 6343,6357 ---- guarantee(!obj->is_objArray(), err_msg("Eagerly reclaiming object arrays is not supported, but the object "PTR_FORMAT" is.", r->bottom())); ! if (G1TraceEagerReclaimHumongousObjects) { ! gclog_or_tty->print_cr("Dead humongous region %u size "SIZE_FORMAT" start "PTR_FORMAT" length "UINT32_FORMAT" with remset "SIZE_FORMAT" code roots "SIZE_FORMAT" is marked %d live-other %d obj array %d", ! region_idx, obj->size()*HeapWordSize, r->bottom(), r->region_num(), r->rem_set()->occupied(), r->rem_set()->strong_code_roots_list_length(), next_bitmap->isMarked(r->bottom()), g1h->humongous_is_live(region_idx),
*** 6344,6355 **** }; void G1CollectedHeap::eagerly_reclaim_humongous_regions() { assert_at_safepoint(true); ! if (!G1ReclaimDeadHumongousObjectsAtYoungGC || ! (!_has_humongous_reclaim_candidates && !G1TraceReclaimDeadHumongousObjectsAtYoungGC)) { g1_policy()->phase_times()->record_fast_reclaim_humongous_time_ms(0.0, 0); return; } double start_time = os::elapsedTime(); --- 6384,6395 ---- }; void G1CollectedHeap::eagerly_reclaim_humongous_regions() { assert_at_safepoint(true); ! if (!G1EagerReclaimHumongousObjects || ! (!_has_humongous_reclaim_candidates && !G1TraceEagerReclaimHumongousObjects)) { g1_policy()->phase_times()->record_fast_reclaim_humongous_time_ms(0.0, 0); return; } double start_time = os::elapsedTime();
< prev index next >