diff --git a/src/share/vm/gc_implementation/g1/g1AllocRegion.cpp b/src/share/vm/gc_implementation/g1/g1AllocRegion.cpp index 5d0d916c48d1124e6b6bcc21a412721bd5c73239..ca31817197b8f763e1a78305b60e3201a3af90a6 100644 --- a/src/share/vm/gc_implementation/g1/g1AllocRegion.cpp +++ b/src/share/vm/gc_implementation/g1/g1AllocRegion.cpp @@ -129,6 +129,7 @@ HeapWord* G1AllocRegion::new_alloc_region_and_allocate(size_t word_size, // region in _alloc_region. This is the reason why an active region // can never be empty. _alloc_region = new_alloc_region; + _count += 1; trace("region allocation successful"); return result; } else { @@ -139,8 +140,8 @@ HeapWord* G1AllocRegion::new_alloc_region_and_allocate(size_t word_size, } void G1AllocRegion::fill_in_ext_msg(ar_ext_msg* msg, const char* message) { - msg->append("[%s] %s b: %s r: "PTR_FORMAT" u: "SIZE_FORMAT, - _name, message, BOOL_TO_STR(_bot_updates), + msg->append("[%s] %s c: "SIZE_FORMAT" b: %s r: "PTR_FORMAT" u: "SIZE_FORMAT, + _name, message, _count, BOOL_TO_STR(_bot_updates), _alloc_region, _used_bytes_before); } @@ -148,16 +149,34 @@ void G1AllocRegion::init() { trace("initializing"); assert(_alloc_region == NULL && _used_bytes_before == 0, ar_ext_msg(this, "pre-condition")); - assert(_dummy_region != NULL, "should have been set"); + assert(_dummy_region != NULL, ar_ext_msg(this, "should have been set")); _alloc_region = _dummy_region; + _count = 0; trace("initialized"); } +void G1AllocRegion::set(HeapRegion* alloc_region) { + trace("setting"); + // We explicitly check that the region is not empty to make sure we + // maintain the "the alloc region cannot be empty" invariant. + assert(alloc_region != NULL && !alloc_region->is_empty(), + ar_ext_msg(this, "pre-condition")); + assert(_alloc_region == _dummy_region && + _used_bytes_before == 0 && _count == 0, + ar_ext_msg(this, "pre-condition")); + + _used_bytes_before = alloc_region->used(); + _alloc_region = alloc_region; + _count += 1; + trace("set"); +} + HeapRegion* G1AllocRegion::release() { trace("releasing"); HeapRegion* alloc_region = _alloc_region; retire(false /* fill_up */); - assert(_alloc_region == _dummy_region, "post-condition of retire()"); + assert(_alloc_region == _dummy_region, + ar_ext_msg(this, "post-condition of retire()")); _alloc_region = NULL; trace("released"); return (alloc_region == _dummy_region) ? NULL : alloc_region; @@ -196,7 +215,8 @@ void G1AllocRegion::trace(const char* str, size_t word_size, HeapWord* result) { jio_snprintf(rest_buffer, buffer_length, ""); } - tty->print_cr("[%s] %s : %s %s", _name, hr_buffer, str, rest_buffer); + tty->print_cr("[%s] "SIZE_FORMAT" %s : %s %s", + _name, _count, hr_buffer, str, rest_buffer); } } #endif // G1_ALLOC_REGION_TRACING @@ -204,5 +224,5 @@ void G1AllocRegion::trace(const char* str, size_t word_size, HeapWord* result) { G1AllocRegion::G1AllocRegion(const char* name, bool bot_updates) : _name(name), _bot_updates(bot_updates), - _alloc_region(NULL), _used_bytes_before(0) { } + _alloc_region(NULL), _count(0), _used_bytes_before(0) { } diff --git a/src/share/vm/gc_implementation/g1/g1AllocRegion.hpp b/src/share/vm/gc_implementation/g1/g1AllocRegion.hpp index d329d1ed5434873ac903a762b712fb8bc8a17553..caf7ff9888f0d428036db53a88bf54d19b1b8f22 100644 --- a/src/share/vm/gc_implementation/g1/g1AllocRegion.hpp +++ b/src/share/vm/gc_implementation/g1/g1AllocRegion.hpp @@ -36,7 +36,7 @@ class ar_ext_msg; // A class that holds a region that is active in satisfying allocation // requests, potentially issued in parallel. When the active region is -// full it will be retired it replaced with a new one. The +// full it will be retired and replaced with a new one. The // implementation assumes that fast-path allocations will be lock-free // and a lock will need to be taken when the active region needs to be // replaced. @@ -57,13 +57,22 @@ private: // correct use of init() and release()). HeapRegion* _alloc_region; + // It keeps track of the distinct number of regions that are used + // for allocation in the active interval of this object, i.e., + // between a call to init() and a call to release(). The count + // mostly includes regions that are freshly allocated, as well as + // the region that is re-used using the set() method. This count can + // be used in any heuristics that might want to bound how many + // distinct regions this object can used during an active interval. + size_t _count; + // When we set up a new active region we save its used bytes in this // field so that, when we retire it, we can calculate how much space // we allocated in it. size_t _used_bytes_before; - // Specifies whether the allocate calls will do BOT updates or not. - bool _bot_updates; + // When true, indicates that allocate calls should do BOT updates. + const bool _bot_updates; // Useful for debugging and tracing. const char* _name; @@ -127,6 +136,8 @@ public: return (_alloc_region == _dummy_region) ? NULL : _alloc_region; } + size_t count() { return _count; } + // The following two are the building blocks for the allocation method. // First-level allocation: Should be called without holding a @@ -153,6 +164,12 @@ public: // Should be called before we start using this object. void init(); + // This can be used to set the active region to a specific + // region. (Use Example: we try to retain the last old GC alloc + // region that we've used during a GC and we can use set() to + // re-instate it at the beginning of the next GC.) + void set(HeapRegion* alloc_region); + // Should be called when we want to release the active region which // is returned after it's been retired. HeapRegion* release(); diff --git a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index 60fc14a4cc44d6b2bbfe3ec4578032affe2b27e6..fc13e58f0f8121166e9611345fd7195b1565ff61 100644 --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -587,26 +587,6 @@ HeapRegion* G1CollectedHeap::new_region(size_t word_size, bool do_expand) { return res; } -HeapRegion* G1CollectedHeap::new_gc_alloc_region(int purpose, - size_t word_size) { - HeapRegion* alloc_region = NULL; - if (_gc_alloc_region_counts[purpose] < g1_policy()->max_regions(purpose)) { - alloc_region = new_region(word_size, true /* do_expand */); - if (alloc_region != NULL) { - if (purpose == GCAllocForSurvived) { - _hr_printer.alloc(alloc_region, G1HRPrinter::Survivor); - alloc_region->set_survivor(); - } else { - _hr_printer.alloc(alloc_region, G1HRPrinter::Old); - } - ++_gc_alloc_region_counts[purpose]; - } - } else { - g1_policy()->note_alloc_region_limit_reached(purpose); - } - return alloc_region; -} - size_t G1CollectedHeap::humongous_obj_allocate_find_first(size_t num_regions, size_t word_size) { assert(isHumongous(word_size), "word_size should be humongous"); @@ -1091,12 +1071,6 @@ HeapWord* G1CollectedHeap::attempt_allocation_at_safepoint(size_t word_size, ShouldNotReachHere(); } -void G1CollectedHeap::abandon_gc_alloc_regions() { - // first, make sure that the GC alloc region list is empty (it should!) - assert(_gc_alloc_region_list == NULL, "invariant"); - release_gc_alloc_regions(true /* totally */); -} - class PostMCRemSetClearClosure: public HeapRegionClosure { ModRefBarrierSet* _mr_bs; public: @@ -1781,7 +1755,11 @@ void G1CollectedHeap::shrink_helper(size_t shrink_bytes) { void G1CollectedHeap::shrink(size_t shrink_bytes) { verify_region_sets_optional(); - release_gc_alloc_regions(true /* totally */); + // We should only reach here at the end of a Full GC which means we + // should not not be holding to any GC alloc regions. The method + // below will make sure of that and do any remaining clean up. + abandon_gc_alloc_regions(); + // Instead of tearing down / rebuilding the free lists here, we // could instead use the remove_all_pending() method on free_list to // remove only the ones that we need to remove. @@ -1821,6 +1799,7 @@ G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* policy_) : _free_regions_coming(false), _young_list(new YoungList(this)), _gc_time_stamp(0), + _retained_old_gc_alloc_region(NULL), _surviving_young_words(NULL), _full_collections_completed(0), _in_cset_fast_test(NULL), @@ -1852,20 +1831,6 @@ G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* policy_) : _task_queues->register_queue(i, q); } - for (int ap = 0; ap < GCAllocPurposeCount; ++ap) { - _gc_alloc_regions[ap] = NULL; - _gc_alloc_region_counts[ap] = 0; - _retained_gc_alloc_regions[ap] = NULL; - // by default, we do not retain a GC alloc region for each ap; - // we'll override this, when appropriate, below - _retain_gc_alloc_region[ap] = false; - } - - // We will try to remember the last half-full tenured region we - // allocated to at the end of a collection so that we can re-use it - // during the next collection. - _retain_gc_alloc_region[GCAllocForTenured] = true; - guarantee(_task_queues != NULL, "task_queues allocation failure."); } @@ -2083,8 +2048,6 @@ jint G1CollectedHeap::initialize() { // counts and that mechanism. SpecializationStats::clear(); - _gc_alloc_region_list = NULL; - // Do later initialization work for concurrent refinement. _cg1r->init(); @@ -2205,27 +2168,6 @@ size_t G1CollectedHeap::recalculate_used() const { return blk.result(); } -#ifndef PRODUCT -class SumUsedRegionsClosure: public HeapRegionClosure { - size_t _num; -public: - SumUsedRegionsClosure() : _num(0) {} - bool doHeapRegion(HeapRegion* r) { - if (r->continuesHumongous() || r->used() > 0 || r->is_gc_alloc_region()) { - _num += 1; - } - return false; - } - size_t result() { return _num; } -}; - -size_t G1CollectedHeap::recalculate_used_regions() const { - SumUsedRegionsClosure blk; - heap_region_iterate(&blk); - return blk.result(); -} -#endif // PRODUCT - size_t G1CollectedHeap::unsafe_max_alloc() { if (free_regions() > 0) return HeapRegion::GrainBytes; // otherwise, is there space in the current allocation region? @@ -3408,8 +3350,6 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { append_secondary_free_list_if_not_empty_with_lock(); } - increment_gc_time_stamp(); - if (g1_policy()->in_young_gc_mode()) { assert(check_young_list_well_formed(), "young list should be well formed"); @@ -3420,6 +3360,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { gc_prologue(false); increment_total_collections(false /* full gc */); + increment_gc_time_stamp(); if (VerifyBeforeGC && total_collections() >= VerifyGCStartAt) { HandleMark hm; // Discard invalid handles created during verification @@ -3472,7 +3413,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { if (g1_policy()->during_initial_mark_pause()) { concurrent_mark()->checkpointRootsInitialPre(); } - save_marks(); + perm_gen()->save_marks(); // We must do this before any possible evacuation that should propagate // marks. @@ -3534,8 +3475,8 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { setup_surviving_young_words(); - // Set up the gc allocation regions. - get_gc_alloc_regions(); + // Initialize the GC alloc regions. + init_gc_alloc_regions(); // Actually do the work... evacuate_collection_set(); @@ -3580,7 +3521,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { } else { // The "used" of the the collection set have already been subtracted // when they were freed. Add in the bytes evacuated. - _summary_bytes_used += g1_policy()->bytes_in_to_space(); + _summary_bytes_used += g1_policy()->bytes_copied_during_gc(); } if (g1_policy()->in_young_gc_mode() && @@ -3614,6 +3555,29 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { MemoryService::track_memory_usage(); + // In prepare_for_verify() below we'll need to scan the deferred + // update buffers to bring the RSets up-to-date if + // G1HRRSFlushLogBuffersOnVerify has been set. While scanning + // the update buffers we'll probably need to scan cards on the + // regions we just allocated to (i.e., the GC alloc + // regions). However, during the last GC we called + // set_saved_mark() on all the GC alloc regions, so card + // scanning might skip the [saved_mark_word()...top()] area of + // those regions (i.e., the area we allocated objects into + // during the last GC). But it shouldn't. Given that + // saved_mark_word() is conditional on whether the GC time stamp + // on the region is current or not, by incrementing the GC time + // stamp here we invalidate all the GC time stamps on all the + // regions and saved_mark_word() will simply return top() for + // all the regions. This is a nicer way of ensuring this rather + // than iterating over the regions and fixing them. In fact, the + // GC time stamp increment here also ensures that + // saved_mark_word() will return top() between pauses, i.e., + // during concurrent refinement. So we don't need the + // is_gc_active() check to decided which top to use when + // scanning cards (see CR 7039627). + increment_gc_time_stamp(); + if (VerifyAfterGC && total_collections() >= VerifyGCStartAt) { HandleMark hm; // Discard invalid handles created during verification gclog_or_tty->print(" VerifyAfterGC:"); @@ -3713,251 +3677,49 @@ void G1CollectedHeap::release_mutator_alloc_region() { assert(_mutator_alloc_region.get() == NULL, "post-condition"); } -void G1CollectedHeap::set_gc_alloc_region(int purpose, HeapRegion* r) { - assert(purpose >= 0 && purpose < GCAllocPurposeCount, "invalid purpose"); - // make sure we don't call set_gc_alloc_region() multiple times on - // the same region - assert(r == NULL || !r->is_gc_alloc_region(), - "shouldn't already be a GC alloc region"); - assert(r == NULL || !r->isHumongous(), - "humongous regions shouldn't be used as GC alloc regions"); - - HeapWord* original_top = NULL; - if (r != NULL) - original_top = r->top(); - - // We will want to record the used space in r as being there before gc. - // One we install it as a GC alloc region it's eligible for allocation. - // So record it now and use it later. - size_t r_used = 0; - if (r != NULL) { - r_used = r->used(); - - if (G1CollectedHeap::use_parallel_gc_threads()) { - // need to take the lock to guard against two threads calling - // get_gc_alloc_region concurrently (very unlikely but...) - MutexLockerEx x(ParGCRareEvent_lock, Mutex::_no_safepoint_check_flag); - r->save_marks(); - } - } - HeapRegion* old_alloc_region = _gc_alloc_regions[purpose]; - _gc_alloc_regions[purpose] = r; - if (old_alloc_region != NULL) { - // Replace aliases too. - for (int ap = 0; ap < GCAllocPurposeCount; ++ap) { - if (_gc_alloc_regions[ap] == old_alloc_region) { - _gc_alloc_regions[ap] = r; - } - } - } - if (r != NULL) { - push_gc_alloc_region(r); - if (mark_in_progress() && original_top != r->next_top_at_mark_start()) { - // We are using a region as a GC alloc region after it has been used - // as a mutator allocation region during the current marking cycle. - // The mutator-allocated objects are currently implicitly marked, but - // when we move hr->next_top_at_mark_start() forward at the the end - // of the GC pause, they won't be. We therefore mark all objects in - // the "gap". We do this object-by-object, since marking densely - // does not currently work right with marking bitmap iteration. This - // means we rely on TLAB filling at the start of pauses, and no - // "resuscitation" of filled TLAB's. If we want to do this, we need - // to fix the marking bitmap iteration. - HeapWord* curhw = r->next_top_at_mark_start(); - HeapWord* t = original_top; - - while (curhw < t) { - oop cur = (oop)curhw; - // We'll assume parallel for generality. This is rare code. - concurrent_mark()->markAndGrayObjectIfNecessary(cur); // can't we just mark them? - curhw = curhw + cur->size(); - } - assert(curhw == t, "Should have parsed correctly."); - } - if (G1PolicyVerbose > 1) { - gclog_or_tty->print("New alloc region ["PTR_FORMAT", "PTR_FORMAT", " PTR_FORMAT") " - "for survivors:", r->bottom(), original_top, r->end()); - r->print(); - } - g1_policy()->record_before_bytes(r_used); - } -} - -void G1CollectedHeap::push_gc_alloc_region(HeapRegion* hr) { - assert(Thread::current()->is_VM_thread() || - FreeList_lock->owned_by_self(), "Precondition"); - assert(!hr->is_gc_alloc_region() && !hr->in_collection_set(), - "Precondition."); - hr->set_is_gc_alloc_region(true); - hr->set_next_gc_alloc_region(_gc_alloc_region_list); - _gc_alloc_region_list = hr; -} - -#ifdef G1_DEBUG -class FindGCAllocRegion: public HeapRegionClosure { -public: - bool doHeapRegion(HeapRegion* r) { - if (r->is_gc_alloc_region()) { - gclog_or_tty->print_cr("Region "HR_FORMAT" is still a GC alloc region", - HR_FORMAT_PARAMS(r)); - } - return false; - } -}; -#endif // G1_DEBUG - -void G1CollectedHeap::forget_alloc_region_list() { +void G1CollectedHeap::init_gc_alloc_regions() { assert_at_safepoint(true /* should_be_vm_thread */); - while (_gc_alloc_region_list != NULL) { - HeapRegion* r = _gc_alloc_region_list; - assert(r->is_gc_alloc_region(), "Invariant."); - // We need HeapRegion::oops_on_card_seq_iterate_careful() to work on - // newly allocated data in order to be able to apply deferred updates - // before the GC is done for verification purposes (i.e to allow - // G1HRRSFlushLogBuffersOnVerify). It's safe thing to do after the - // collection. - r->ContiguousSpace::set_saved_mark(); - _gc_alloc_region_list = r->next_gc_alloc_region(); - r->set_next_gc_alloc_region(NULL); - r->set_is_gc_alloc_region(false); - if (r->is_survivor()) { - if (r->is_empty()) { - r->set_not_young(); - } else { - _young_list->add_survivor_region(r); - } - } - } -#ifdef G1_DEBUG - FindGCAllocRegion fa; - heap_region_iterate(&fa); -#endif // G1_DEBUG -} - -bool G1CollectedHeap::check_gc_alloc_regions() { - // TODO: allocation regions check - return true; + _survivor_gc_alloc_region.init(); + _old_gc_alloc_region.init(); + HeapRegion* retained_region = _retained_old_gc_alloc_region; + _retained_old_gc_alloc_region = NULL; + + // We will discard the current GC alloc region if: + // a) it's in the collection set (it can happen!), + // b) it's already full (no point in using it), + // c) it's empty (this means that it was emptied during + // a cleanup and it should be on the free list now), or + // d) it's humongous (this means that it was emptied + // during a cleanup and was added to the free list, but + // has been subseqently used to allocate a humongous + // object that may be less than the region size). + if (retained_region != NULL && + !retained_region->in_collection_set() && + !(retained_region->top() == retained_region->end()) && + !retained_region->is_empty() && + !retained_region->isHumongous()) { + retained_region->set_saved_mark(); + _old_gc_alloc_region.set(retained_region); + _hr_printer.reuse(retained_region); + } +} + +void G1CollectedHeap::release_gc_alloc_regions() { + _survivor_gc_alloc_region.release(); + // If we have an old GC alloc region to release, we'll save it in + // _retained_old_gc_alloc_region. If we don't + // _retained_old_gc_alloc_region will become NULL. This is what we + // want either way so no reason to check explicitly for either + // condition. + _retained_old_gc_alloc_region = _old_gc_alloc_region.release(); } -void G1CollectedHeap::get_gc_alloc_regions() { - // First, let's check that the GC alloc region list is empty (it should) - assert(_gc_alloc_region_list == NULL, "invariant"); - - for (int ap = 0; ap < GCAllocPurposeCount; ++ap) { - assert(_gc_alloc_regions[ap] == NULL, "invariant"); - assert(_gc_alloc_region_counts[ap] == 0, "invariant"); - - // Create new GC alloc regions. - HeapRegion* alloc_region = _retained_gc_alloc_regions[ap]; - _retained_gc_alloc_regions[ap] = NULL; - - if (alloc_region != NULL) { - assert(_retain_gc_alloc_region[ap], "only way to retain a GC region"); - - // let's make sure that the GC alloc region is not tagged as such - // outside a GC operation - assert(!alloc_region->is_gc_alloc_region(), "sanity"); - - if (alloc_region->in_collection_set() || - alloc_region->top() == alloc_region->end() || - alloc_region->top() == alloc_region->bottom() || - alloc_region->isHumongous()) { - // we will discard the current GC alloc region if - // * it's in the collection set (it can happen!), - // * it's already full (no point in using it), - // * it's empty (this means that it was emptied during - // a cleanup and it should be on the free list now), or - // * it's humongous (this means that it was emptied - // during a cleanup and was added to the free list, but - // has been subseqently used to allocate a humongous - // object that may be less than the region size). - - alloc_region = NULL; - } - } - - if (alloc_region == NULL) { - // we will get a new GC alloc region - alloc_region = new_gc_alloc_region(ap, HeapRegion::GrainWords); - } else { - // the region was retained from the last collection - ++_gc_alloc_region_counts[ap]; - - _hr_printer.reuse(alloc_region); - } - - if (alloc_region != NULL) { - assert(_gc_alloc_regions[ap] == NULL, "pre-condition"); - set_gc_alloc_region(ap, alloc_region); - } - - assert(_gc_alloc_regions[ap] == NULL || - _gc_alloc_regions[ap]->is_gc_alloc_region(), - "the GC alloc region should be tagged as such"); - assert(_gc_alloc_regions[ap] == NULL || - _gc_alloc_regions[ap] == _gc_alloc_region_list, - "the GC alloc region should be the same as the GC alloc list head"); - } - // Set alternative regions for allocation purposes that have reached - // their limit. - for (int ap = 0; ap < GCAllocPurposeCount; ++ap) { - GCAllocPurpose alt_purpose = g1_policy()->alternative_purpose(ap); - if (_gc_alloc_regions[ap] == NULL && alt_purpose != ap) { - _gc_alloc_regions[ap] = _gc_alloc_regions[alt_purpose]; - } - } - assert(check_gc_alloc_regions(), "alloc regions messed up"); -} - -void G1CollectedHeap::release_gc_alloc_regions(bool totally) { - // We keep a separate list of all regions that have been alloc regions in - // the current collection pause. Forget that now. This method will - // untag the GC alloc regions and tear down the GC alloc region - // list. It's desirable that no regions are tagged as GC alloc - // outside GCs. - - forget_alloc_region_list(); - - // The current alloc regions contain objs that have survived - // collection. Make them no longer GC alloc regions. - for (int ap = 0; ap < GCAllocPurposeCount; ++ap) { - HeapRegion* r = _gc_alloc_regions[ap]; - _retained_gc_alloc_regions[ap] = NULL; - _gc_alloc_region_counts[ap] = 0; - - if (r != NULL) { - // we retain nothing on _gc_alloc_regions between GCs - set_gc_alloc_region(ap, NULL); - - if (r->is_empty()) { - // We didn't actually allocate anything in it; let's just put - // it back on the free list. - _free_list.add_as_head(r); - } else if (_retain_gc_alloc_region[ap] && !totally) { - // retain it so that we can use it at the beginning of the next GC - _retained_gc_alloc_regions[ap] = r; - } - } - } -} - -#ifndef PRODUCT -// Useful for debugging - -void G1CollectedHeap::print_gc_alloc_regions() { - gclog_or_tty->print_cr("GC alloc regions"); - for (int ap = 0; ap < GCAllocPurposeCount; ++ap) { - HeapRegion* r = _gc_alloc_regions[ap]; - if (r == NULL) { - gclog_or_tty->print_cr(" %2d : "PTR_FORMAT, ap, NULL); - } else { - gclog_or_tty->print_cr(" %2d : "PTR_FORMAT" "SIZE_FORMAT, - ap, r->bottom(), r->used()); - } - } +void G1CollectedHeap::abandon_gc_alloc_regions() { + assert(_survivor_gc_alloc_region.get() == NULL, "pre-condition"); + assert(_old_gc_alloc_region.get() == NULL, "pre-condition"); + _retained_old_gc_alloc_region = NULL; } -#endif // PRODUCT void G1CollectedHeap::init_for_evac_failure(OopsInHeapRegionClosure* cl) { _drain_in_progress = false; @@ -3974,8 +3736,6 @@ void G1CollectedHeap::finalize_for_evac_failure() { _evac_failure_scan_stack = NULL; } - - // *** Sequential G1 Evacuation class G1IsAliveClosure: public BoolObjectClosure { @@ -4287,136 +4047,32 @@ void G1CollectedHeap::preserve_mark_if_necessary(oop obj, markOop m) { } } -// *** Parallel G1 Evacuation - HeapWord* G1CollectedHeap::par_allocate_during_gc(GCAllocPurpose purpose, size_t word_size) { - assert(!isHumongous(word_size), - err_msg("we should not be seeing humongous allocation requests " - "during GC, word_size = "SIZE_FORMAT, word_size)); - - HeapRegion* alloc_region = _gc_alloc_regions[purpose]; - // let the caller handle alloc failure - if (alloc_region == NULL) return NULL; - - HeapWord* block = alloc_region->par_allocate(word_size); - if (block == NULL) { - block = allocate_during_gc_slow(purpose, alloc_region, true, word_size); - } - return block; -} - -void G1CollectedHeap::retire_alloc_region(HeapRegion* alloc_region, - bool par) { - // Another thread might have obtained alloc_region for the given - // purpose, and might be attempting to allocate in it, and might - // succeed. Therefore, we can't do the "finalization" stuff on the - // region below until we're sure the last allocation has happened. - // We ensure this by allocating the remaining space with a garbage - // object. - if (par) par_allocate_remaining_space(alloc_region); - // Now we can do the post-GC stuff on the region. - alloc_region->note_end_of_copying(); - g1_policy()->record_after_bytes(alloc_region->used()); - _hr_printer.retire(alloc_region); -} - -HeapWord* -G1CollectedHeap::allocate_during_gc_slow(GCAllocPurpose purpose, - HeapRegion* alloc_region, - bool par, - size_t word_size) { - assert(!isHumongous(word_size), - err_msg("we should not be seeing humongous allocation requests " - "during GC, word_size = "SIZE_FORMAT, word_size)); - - // We need to make sure we serialize calls to this method. Given - // that the FreeList_lock guards accesses to the free_list anyway, - // and we need to potentially remove a region from it, we'll use it - // to protect the whole call. - MutexLockerEx x(FreeList_lock, Mutex::_no_safepoint_check_flag); - - HeapWord* block = NULL; - // In the parallel case, a previous thread to obtain the lock may have - // already assigned a new gc_alloc_region. - if (alloc_region != _gc_alloc_regions[purpose]) { - assert(par, "But should only happen in parallel case."); - alloc_region = _gc_alloc_regions[purpose]; - if (alloc_region == NULL) return NULL; - block = alloc_region->par_allocate(word_size); - if (block != NULL) return block; - // Otherwise, continue; this new region is empty, too. - } - assert(alloc_region != NULL, "We better have an allocation region"); - retire_alloc_region(alloc_region, par); - - if (_gc_alloc_region_counts[purpose] >= g1_policy()->max_regions(purpose)) { - // Cannot allocate more regions for the given purpose. - GCAllocPurpose alt_purpose = g1_policy()->alternative_purpose(purpose); - // Is there an alternative? - if (purpose != alt_purpose) { - HeapRegion* alt_region = _gc_alloc_regions[alt_purpose]; - // Has not the alternative region been aliased? - if (alloc_region != alt_region && alt_region != NULL) { - // Try to allocate in the alternative region. - if (par) { - block = alt_region->par_allocate(word_size); - } else { - block = alt_region->allocate(word_size); - } - // Make an alias. - _gc_alloc_regions[purpose] = _gc_alloc_regions[alt_purpose]; - if (block != NULL) { - return block; - } - retire_alloc_region(alt_region, par); - } - // Both the allocation region and the alternative one are full - // and aliased, replace them with a new allocation region. - purpose = alt_purpose; + if (purpose == GCAllocForSurvived) { + HeapWord* result = survivor_attempt_allocation(word_size); + if (result != NULL) { + return result; } else { - set_gc_alloc_region(purpose, NULL); - return NULL; + // Let's try to allocate in the old gen in case we can fit the + // object there. + return old_attempt_allocation(word_size); } - } - - // Now allocate a new region for allocation. - alloc_region = new_gc_alloc_region(purpose, word_size); - - // let the caller handle alloc failure - if (alloc_region != NULL) { - - assert(check_gc_alloc_regions(), "alloc regions messed up"); - assert(alloc_region->saved_mark_at_top(), - "Mark should have been saved already."); - // This must be done last: once it's installed, other regions may - // allocate in it (without holding the lock.) - set_gc_alloc_region(purpose, alloc_region); - - if (par) { - block = alloc_region->par_allocate(word_size); + } else { + assert(purpose == GCAllocForTenured, "sanity"); + HeapWord* result = old_attempt_allocation(word_size); + if (result != NULL) { + return result; } else { - block = alloc_region->allocate(word_size); + // Let's try to allocate in the survivors in case we can fit the + // object there. + return survivor_attempt_allocation(word_size); } - // Caller handles alloc failure. - } else { - // This sets other apis using the same old alloc region to NULL, also. - set_gc_alloc_region(purpose, NULL); } - return block; // May be NULL. -} -void G1CollectedHeap::par_allocate_remaining_space(HeapRegion* r) { - HeapWord* block = NULL; - size_t free_words; - do { - free_words = r->free()/HeapWordSize; - // If there's too little space, no one can allocate, so we're done. - if (free_words < CollectedHeap::min_fill_size()) return; - // Otherwise, try to claim it. - block = r->par_allocate(free_words); - } while (block == NULL); - fill_with_object(block, free_words); + ShouldNotReachHere(); + // Trying to keep some compilers happy. + return NULL; } #ifndef PRODUCT @@ -4956,24 +4612,6 @@ G1CollectedHeap::g1_process_weak_roots(OopClosure* root_closure, SharedHeap::process_weak_roots(root_closure, &roots_in_blobs, non_root_closure); } - -class SaveMarksClosure: public HeapRegionClosure { -public: - bool doHeapRegion(HeapRegion* r) { - r->save_marks(); - return false; - } -}; - -void G1CollectedHeap::save_marks() { - if (!CollectedHeap::use_parallel_gc_threads()) { - SaveMarksClosure sm; - heap_region_iterate(&sm); - } - // We do this even in the parallel case - perm_gen()->save_marks(); -} - void G1CollectedHeap::evacuate_collection_set() { set_evacuation_failed(false); @@ -5004,10 +4642,6 @@ void G1CollectedHeap::evacuate_collection_set() { double par_time = (os::elapsedTime() - start_par) * 1000.0; g1_policy()->record_par_time(par_time); set_par_threads(0); - // Is this the right thing to do here? We don't save marks - // on individual heap regions when we allocate from - // them in parallel, so this seems like the correct place for this. - retire_all_alloc_regions(); // Weak root processing. // Note: when JSR 292 is enabled and code blobs can contain @@ -5018,7 +4652,7 @@ void G1CollectedHeap::evacuate_collection_set() { G1KeepAliveClosure keep_alive(this); JNIHandles::weak_oops_do(&is_alive, &keep_alive); } - release_gc_alloc_regions(false /* totally */); + release_gc_alloc_regions(); g1_rem_set()->cleanup_after_oops_into_collection_set_do(); concurrent_g1_refine()->clear_hot_cache(); @@ -5139,68 +4773,31 @@ void G1CollectedHeap::update_sets_after_freeing_regions(size_t pre_used, } } -void G1CollectedHeap::dirtyCardsForYoungRegions(CardTableModRefBS* ct_bs, HeapRegion* list) { - while (list != NULL) { - guarantee( list->is_young(), "invariant" ); - - HeapWord* bottom = list->bottom(); - HeapWord* end = list->end(); - MemRegion mr(bottom, end); - ct_bs->dirty(mr); - - list = list->get_next_young_region(); - } -} - - class G1ParCleanupCTTask : public AbstractGangTask { CardTableModRefBS* _ct_bs; G1CollectedHeap* _g1h; HeapRegion* volatile _su_head; public: G1ParCleanupCTTask(CardTableModRefBS* ct_bs, - G1CollectedHeap* g1h, - HeapRegion* survivor_list) : + G1CollectedHeap* g1h) : AbstractGangTask("G1 Par Cleanup CT Task"), - _ct_bs(ct_bs), - _g1h(g1h), - _su_head(survivor_list) - { } + _ct_bs(ct_bs), _g1h(g1h) { } void work(int i) { HeapRegion* r; while (r = _g1h->pop_dirty_cards_region()) { clear_cards(r); } - // Redirty the cards of the survivor regions. - dirty_list(&this->_su_head); } void clear_cards(HeapRegion* r) { - // Cards for Survivor regions will be dirtied later. + // Cards of the survivors should have already been dirtied. if (!r->is_survivor()) { _ct_bs->clear(MemRegion(r->bottom(), r->end())); } } - - void dirty_list(HeapRegion* volatile * head_ptr) { - HeapRegion* head; - do { - // Pop region off the list. - head = *head_ptr; - if (head != NULL) { - HeapRegion* r = (HeapRegion*) - Atomic::cmpxchg_ptr(head->get_next_young_region(), head_ptr, head); - if (r == head) { - assert(!r->isHumongous(), "Humongous regions shouldn't be on survivor list"); - _ct_bs->dirty(MemRegion(r->bottom(), r->end())); - } - } - } while (*head_ptr != NULL); - } }; - #ifndef PRODUCT class G1VerifyCardTableCleanup: public HeapRegionClosure { G1CollectedHeap* _g1h; @@ -5256,8 +4853,7 @@ void G1CollectedHeap::cleanUpCardTable() { double start = os::elapsedTime(); // Iterate over the dirty cards region list. - G1ParCleanupCTTask cleanup_task(ct_bs, this, - _young_list->first_survivor_region()); + G1ParCleanupCTTask cleanup_task(ct_bs, this); if (ParallelGCThreads > 0) { set_par_threads(workers()->total_workers()); @@ -5274,10 +4870,6 @@ void G1CollectedHeap::cleanUpCardTable() { } r->set_next_dirty_cards_region(NULL); } - // now, redirty the cards of the survivor regions - // (it seemed faster to do it this way, instead of iterating over - // all regions and then clearing / dirtying as appropriate) - dirtyCardsForYoungRegions(ct_bs, _young_list->first_survivor_region()); } double elapsed = os::elapsedTime() - start; @@ -5504,34 +5096,6 @@ void G1CollectedHeap::empty_young_list() { _young_list->empty_list(); } -bool G1CollectedHeap::all_alloc_regions_no_allocs_since_save_marks() { - bool no_allocs = true; - for (int ap = 0; ap < GCAllocPurposeCount && no_allocs; ++ap) { - HeapRegion* r = _gc_alloc_regions[ap]; - no_allocs = r == NULL || r->saved_mark_at_top(); - } - return no_allocs; -} - -void G1CollectedHeap::retire_all_alloc_regions() { - for (int ap = 0; ap < GCAllocPurposeCount; ++ap) { - HeapRegion* r = _gc_alloc_regions[ap]; - if (r != NULL) { - // Check for aliases. - bool has_processed_alias = false; - for (int i = 0; i < ap; ++i) { - if (_gc_alloc_regions[i] == r) { - has_processed_alias = true; - break; - } - } - if (!has_processed_alias) { - retire_alloc_region(r, false /* par */); - } - } - } -} - // Done at the start of full GC. void G1CollectedHeap::tear_down_region_lists() { _free_list.remove_all(); @@ -5586,6 +5150,8 @@ bool G1CollectedHeap::is_in_closed_subset(const void* p) const { } } +// Methods for the mutator alloc region + HeapRegion* G1CollectedHeap::new_mutator_alloc_region(size_t word_size, bool force) { assert_heap_locked_or_at_safepoint(true /* should_be_vm_thread */); @@ -5626,6 +5192,69 @@ void MutatorAllocRegion::retire_region(HeapRegion* alloc_region, _g1h->retire_mutator_alloc_region(alloc_region, allocated_bytes); } +// Methods for the GC alloc regions + +HeapRegion* G1CollectedHeap::new_gc_alloc_region(size_t word_size, + size_t count, + GCAllocPurpose ap) { + assert(FreeList_lock->owned_by_self(), "pre-condition"); + + if (count < g1_policy()->max_regions(ap)) { + HeapRegion* new_alloc_region = new_region(word_size, + true /* do_expand */); + if (new_alloc_region != NULL) { + // We really only need to do this for old regions given that we + // should never scan survivors. But it doesn't hurt to do it + // for survivors too. + new_alloc_region->set_saved_mark(); + if (ap == GCAllocForSurvived) { + new_alloc_region->set_survivor(); + _hr_printer.alloc(new_alloc_region, G1HRPrinter::Survivor); + } else { + _hr_printer.alloc(new_alloc_region, G1HRPrinter::Old); + } + return new_alloc_region; + } else { + g1_policy()->note_alloc_region_limit_reached(ap); + } + } + return NULL; +} + +void G1CollectedHeap::retire_gc_alloc_region(HeapRegion* alloc_region, + size_t allocated_bytes, + GCAllocPurpose ap) { + alloc_region->note_end_of_copying(); + g1_policy()->record_bytes_copied_during_gc(allocated_bytes); + if (ap == GCAllocForSurvived) { + young_list()->add_survivor_region(alloc_region); + } + _hr_printer.retire(alloc_region); +} + +HeapRegion* SurvivorGCAllocRegion::allocate_new_region(size_t word_size, + bool force) { + assert(!force, "not supported for GC alloc regions"); + return _g1h->new_gc_alloc_region(word_size, count(), GCAllocForSurvived); +} + +void SurvivorGCAllocRegion::retire_region(HeapRegion* alloc_region, + size_t allocated_bytes) { + _g1h->retire_gc_alloc_region(alloc_region, allocated_bytes, + GCAllocForSurvived); +} + +HeapRegion* OldGCAllocRegion::allocate_new_region(size_t word_size, + bool force) { + assert(!force, "not supported for GC alloc regions"); + return _g1h->new_gc_alloc_region(word_size, count(), GCAllocForTenured); +} + +void OldGCAllocRegion::retire_region(HeapRegion* alloc_region, + size_t allocated_bytes) { + _g1h->retire_gc_alloc_region(alloc_region, allocated_bytes, + GCAllocForTenured); +} // Heap region set verification class VerifyRegionListsClosure : public HeapRegionClosure { diff --git a/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp b/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp index 5976805747095bb91ba39bc7ef323d332c28100a..3d79f3376826625b2fad40b74da3abae2a26eae6 100644 --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp @@ -155,6 +155,24 @@ public: : G1AllocRegion("Mutator Alloc Region", false /* bot_updates */) { } }; +class SurvivorGCAllocRegion : public G1AllocRegion { +protected: + virtual HeapRegion* allocate_new_region(size_t word_size, bool force); + virtual void retire_region(HeapRegion* alloc_region, size_t allocated_bytes); +public: + SurvivorGCAllocRegion() + : G1AllocRegion("Survivor GC Alloc Region", false /* bot_updates */) { } +}; + +class OldGCAllocRegion : public G1AllocRegion { +protected: + virtual HeapRegion* allocate_new_region(size_t word_size, bool force); + virtual void retire_region(HeapRegion* alloc_region, size_t allocated_bytes); +public: + OldGCAllocRegion() + : G1AllocRegion("Old GC Alloc Region", true /* bot_updates */) { } +}; + class RefineCardTableEntryClosure; class G1CollectedHeap : public SharedHeap { friend class VM_G1CollectForAllocation; @@ -163,6 +181,8 @@ class G1CollectedHeap : public SharedHeap { friend class VM_G1IncCollectionPause; friend class VMStructs; friend class MutatorAllocRegion; + friend class SurvivorGCAllocRegion; + friend class OldGCAllocRegion; // Closures used in implementation. friend class G1ParCopyHelper; @@ -225,30 +245,33 @@ private: // Alloc region used to satisfy mutator allocation requests. MutatorAllocRegion _mutator_alloc_region; + // Alloc region used to satisfy allocation requests by the GC for + // survivor objects. + SurvivorGCAllocRegion _survivor_gc_alloc_region; + + // Alloc region used to satisfy allocation requests by the GC for + // old objects. + OldGCAllocRegion _old_gc_alloc_region; + + // The last old region we allocated to during the last GC. + // Typically, it is not full so we should re-use it during the next GC. + HeapRegion* _retained_old_gc_alloc_region; + // It resets the mutator alloc region before new allocations can take place. void init_mutator_alloc_region(); // It releases the mutator alloc region. void release_mutator_alloc_region(); - void abandon_gc_alloc_regions(); + // It initializes the GC alloc regions at the start of a GC. + void init_gc_alloc_regions(); - // The to-space memory regions into which objects are being copied during - // a GC. - HeapRegion* _gc_alloc_regions[GCAllocPurposeCount]; - size_t _gc_alloc_region_counts[GCAllocPurposeCount]; - // These are the regions, one per GCAllocPurpose, that are half-full - // at the end of a collection and that we want to reuse during the - // next collection. - HeapRegion* _retained_gc_alloc_regions[GCAllocPurposeCount]; - // This specifies whether we will keep the last half-full region at - // the end of a collection so that it can be reused during the next - // collection (this is specified per GCAllocPurpose) - bool _retain_gc_alloc_region[GCAllocPurposeCount]; - - // A list of the regions that have been set to be alloc regions in the - // current collection. - HeapRegion* _gc_alloc_region_list; + // It releases the GC alloc regions at the end of a GC. + void release_gc_alloc_regions(); + + // It does any cleanup that needs to be done on the GC alloc regions + // before a Full GC. + void abandon_gc_alloc_regions(); // Helper for monitoring and management support. G1MonitoringSupport* _g1mm; @@ -256,20 +279,6 @@ private: // Determines PLAB size for a particular allocation purpose. static size_t desired_plab_sz(GCAllocPurpose purpose); - // When called by par thread, requires the FreeList_lock to be held. - void push_gc_alloc_region(HeapRegion* hr); - - // This should only be called single-threaded. Undeclares all GC alloc - // regions. - void forget_alloc_region_list(); - - // Should be used to set an alloc region, because there's other - // associated bookkeeping. - void set_gc_alloc_region(int purpose, HeapRegion* r); - - // Check well-formedness of alloc region list. - bool check_gc_alloc_regions(); - // Outside of GC pauses, the number of bytes used in all regions other // than the current allocation region. size_t _summary_bytes_used; @@ -387,12 +396,6 @@ private: protected: - // Returns "true" iff none of the gc alloc regions have any allocations - // since the last call to "save_marks". - bool all_alloc_regions_no_allocs_since_save_marks(); - // Perform finalization stuff on all allocation regions. - void retire_all_alloc_regions(); - // The young region list. YoungList* _young_list; @@ -412,11 +415,6 @@ protected: // request. HeapRegion* new_region(size_t word_size, bool do_expand); - // Try to allocate a new region to be used for allocation by - // a GC thread. It will try to expand the heap if no region is - // available. - HeapRegion* new_gc_alloc_region(int purpose, size_t word_size); - // Attempt to satisfy a humongous allocation request of the given // size by finding a contiguous set of free regions of num_regions // length and remove them from the master free list. Return the @@ -524,16 +522,25 @@ protected: // that parallel threads might be attempting allocations. void par_allocate_remaining_space(HeapRegion* r); - // Retires an allocation region when it is full or at the end of a - // GC pause. - void retire_alloc_region(HeapRegion* alloc_region, bool par); + // Allocation attempt during GC for a survivor object / PLAB. + inline HeapWord* survivor_attempt_allocation(size_t word_size); + + // Allocation attempt during GC for an old object / PLAB. + inline HeapWord* old_attempt_allocation(size_t word_size); - // These two methods are the "callbacks" from the G1AllocRegion class. + // These methods are the "callbacks" from the G1AllocRegion class. + // For mutator alloc regions. HeapRegion* new_mutator_alloc_region(size_t word_size, bool force); void retire_mutator_alloc_region(HeapRegion* alloc_region, size_t allocated_bytes); + // For GC alloc regions. + HeapRegion* new_gc_alloc_region(size_t word_size, size_t count, + GCAllocPurpose ap); + void retire_gc_alloc_region(HeapRegion* alloc_region, + size_t allocated_bytes, GCAllocPurpose ap); + // - if explicit_gc is true, the GC is for a System.gc() or a heap // inspection request and should collect the entire heap // - if clear_all_soft_refs is true, all soft references should be @@ -727,9 +734,6 @@ protected: void g1_process_weak_roots(OopClosure* root_closure, OopClosure* non_root_closure); - // Invoke "save_marks" on all heap regions. - void save_marks(); - // Frees a non-humongous region by initializing its contents and // adding it to the free list that's passed as a parameter (this is // usually a local list which will be appended to the master free @@ -821,24 +825,6 @@ protected: oop handle_evacuation_failure_par(OopsInHeapRegionClosure* cl, oop obj); void handle_evacuation_failure_common(oop obj, markOop m); - // Ensure that the relevant gc_alloc regions are set. - void get_gc_alloc_regions(); - // We're done with GC alloc regions. We are going to tear down the - // gc alloc list and remove the gc alloc tag from all the regions on - // that list. However, we will also retain the last (i.e., the one - // that is half-full) GC alloc region, per GCAllocPurpose, for - // possible reuse during the next collection, provided - // _retain_gc_alloc_region[] indicates that it should be the - // case. Said regions are kept in the _retained_gc_alloc_regions[] - // array. If the parameter totally is set, we will not retain any - // regions, irrespective of what _retain_gc_alloc_region[] - // indicates. - void release_gc_alloc_regions(bool totally); -#ifndef PRODUCT - // Useful for debugging. - void print_gc_alloc_regions(); -#endif // !PRODUCT - // Instance of the concurrent mark is_alive closure for embedding // into the reference processor as the is_alive_non_header. This // prevents unnecessary additions to the discovered lists during @@ -947,9 +933,6 @@ public: // result might be a bit inaccurate. size_t used_unlocked() const; size_t recalculate_used() const; -#ifndef PRODUCT - size_t recalculate_used_regions() const; -#endif // PRODUCT // These virtual functions do the actual allocation. // Some heaps may offer a contiguous region for shared non-blocking @@ -1109,9 +1092,6 @@ public: virtual bool is_in_closed_subset(const void* p) const; - // Dirty card table entries covering a list of young regions. - void dirtyCardsForYoungRegions(CardTableModRefBS* ct_bs, HeapRegion* list); - // This resets the card table to all zeros. It is used after // a collection pause which used the card table to claim cards. void cleanUpCardTable(); diff --git a/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp b/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp index 05a42d74e46e6158fc1480f583fb3f436189fb67..ee18c4de450bbc9139ae0320f9c49f5aefcc56a0 100644 --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp @@ -77,6 +77,38 @@ G1CollectedHeap::attempt_allocation(size_t word_size, return result; } +inline HeapWord* G1CollectedHeap::survivor_attempt_allocation(size_t + word_size) { + assert(!isHumongous(word_size), + "we should not be seeing humongous-size allocations in this path"); + + HeapWord* result = _survivor_gc_alloc_region.attempt_allocation(word_size, + false /* bot_updates */); + if (result == NULL) { + MutexLockerEx x(FreeList_lock, Mutex::_no_safepoint_check_flag); + result = _survivor_gc_alloc_region.attempt_allocation_locked(word_size, + false /* bot_updates */); + } + if (result != NULL) { + dirty_young_block(result, word_size); + } + return result; +} + +inline HeapWord* G1CollectedHeap::old_attempt_allocation(size_t word_size) { + assert(!isHumongous(word_size), + "we should not be seeing humongous-size allocations in this path"); + + HeapWord* result = _old_gc_alloc_region.attempt_allocation(word_size, + true /* bot_updates */); + if (result == NULL) { + MutexLockerEx x(FreeList_lock, Mutex::_no_safepoint_check_flag); + result = _old_gc_alloc_region.attempt_allocation_locked(word_size, + true /* bot_updates */); + } + return result; +} + // It dirties the cards that cover the block so that so that the post // write barrier never queues anything when updating objects on this // block. It is assumed (and in fact we assert) that the block diff --git a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp index 2c6dda9a1c709e8597427f3914df408e2f1a11e0..f2d80126535bb4cc2662bd30746dee79cfec9d10 100644 --- a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp +++ b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp @@ -859,14 +859,6 @@ void G1CollectorPolicy::record_full_collection_end() { calculate_young_list_target_length(); } -void G1CollectorPolicy::record_before_bytes(size_t bytes) { - _bytes_in_to_space_before_gc += bytes; -} - -void G1CollectorPolicy::record_after_bytes(size_t bytes) { - _bytes_in_to_space_after_gc += bytes; -} - void G1CollectorPolicy::record_stop_world_start() { _stop_world_start = os::elapsedTime(); } @@ -894,9 +886,8 @@ void G1CollectorPolicy::record_collection_pause_start(double start_time_sec, _pending_cards = _g1->pending_card_num(); _max_pending_cards = _g1->max_pending_card_num(); - _bytes_in_to_space_before_gc = 0; - _bytes_in_to_space_after_gc = 0; _bytes_in_collection_set_before_gc = 0; + _bytes_copied_during_gc = 0; YoungList* young_list = _g1->young_list(); _eden_bytes_before_gc = young_list->eden_used_bytes(); @@ -1578,8 +1569,8 @@ void G1CollectorPolicy::record_collection_pause_end() { double survival_ratio = 0.0; if (_bytes_in_collection_set_before_gc > 0) { - survival_ratio = (double) bytes_in_to_space_during_gc() / - (double) _bytes_in_collection_set_before_gc; + survival_ratio = (double) _bytes_copied_during_gc / + (double) _bytes_in_collection_set_before_gc; } _pending_cards_seq->add((double) _pending_cards); diff --git a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp index 69e3ea9a083a6c8620dec8f50fc160673c2a2a81..02dc70271eeef059a73bdfb325b42ec06df28927 100644 --- a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp +++ b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -585,13 +585,9 @@ protected: int _last_update_rs_processed_buffers; double _last_pause_time_ms; - size_t _bytes_in_to_space_before_gc; - size_t _bytes_in_to_space_after_gc; - size_t bytes_in_to_space_during_gc() { - return - _bytes_in_to_space_after_gc - _bytes_in_to_space_before_gc; - } size_t _bytes_in_collection_set_before_gc; + size_t _bytes_copied_during_gc; + // Used to count used bytes in CS. friend class CountCSClosure; @@ -805,10 +801,6 @@ public: return _bytes_in_collection_set_before_gc; } - size_t bytes_in_to_space() { - return bytes_in_to_space_during_gc(); - } - unsigned calc_gc_alloc_time_stamp() { return _all_pause_times_ms->num() + 1; } @@ -977,9 +969,16 @@ public: } #endif - // Record the fact that "bytes" bytes allocated in a region. - void record_before_bytes(size_t bytes); - void record_after_bytes(size_t bytes); + // Record how much space we copied during a GC. This is typically + // called when a GC alloc region is being retired. + void record_bytes_copied_during_gc(size_t bytes) { + _bytes_copied_during_gc += bytes; + } + + // The amount of space we copied during a GC. + size_t bytes_copied_during_gc() { + return _bytes_copied_during_gc; + } // Choose a new collection set. Marks the chosen regions as being // "in_collection_set", and links them together. The head and number of @@ -1193,10 +1192,6 @@ public: return purpose == GCAllocForSurvived; } - inline GCAllocPurpose alternative_purpose(int purpose) { - return GCAllocForTenured; - } - static const size_t REGIONS_UNLIMITED = ~(size_t)0; size_t max_regions(int purpose); diff --git a/src/share/vm/gc_implementation/g1/heapRegion.cpp b/src/share/vm/gc_implementation/g1/heapRegion.cpp index 3acd1001c40c1729820561ff47d0722a058ba986..ec4231439795e38178092fefa205a5be4ba0dde8 100644 --- a/src/share/vm/gc_implementation/g1/heapRegion.cpp +++ b/src/share/vm/gc_implementation/g1/heapRegion.cpp @@ -352,7 +352,6 @@ void HeapRegion::hr_clear(bool par, bool clear_space) { "we should have already filtered out humongous regions"); _in_collection_set = false; - _is_gc_alloc_region = false; set_young_index_in_cset(-1); uninstall_surv_rate_group(); @@ -486,7 +485,7 @@ HeapRegion(size_t hrs_index, G1BlockOffsetSharedArray* sharedOffsetArray, : G1OffsetTableContigSpace(sharedOffsetArray, mr, is_zeroed), _next_fk(HeapRegionDCTOC::NoFilterKind), _hrs_index(hrs_index), _humongous_type(NotHumongous), _humongous_start_region(NULL), - _in_collection_set(false), _is_gc_alloc_region(false), + _in_collection_set(false), _next_in_special_set(NULL), _orig_end(NULL), _claimed(InitialClaimValue), _evacuation_failed(false), _prev_marked_bytes(0), _next_marked_bytes(0), _sort_index(-1), @@ -716,8 +715,6 @@ void HeapRegion::print_on(outputStream* st) const { } if (in_collection_set()) st->print(" CS"); - else if (is_gc_alloc_region()) - st->print(" A "); else st->print(" "); if (is_young()) diff --git a/src/share/vm/gc_implementation/g1/heapRegion.hpp b/src/share/vm/gc_implementation/g1/heapRegion.hpp index ec63d1fa9da764c067db8fcc33f57d7c9a65aa07..774987dd8afc9339a206debd12eaa8c5970e86ea 100644 --- a/src/share/vm/gc_implementation/g1/heapRegion.hpp +++ b/src/share/vm/gc_implementation/g1/heapRegion.hpp @@ -251,10 +251,6 @@ class HeapRegion: public G1OffsetTableContigSpace { // True iff the region is in current collection_set. bool _in_collection_set; - // Is this or has it been an allocation region in the current collection - // pause. - bool _is_gc_alloc_region; - // True iff an attempt to evacuate an object in the region failed. bool _evacuation_failed; @@ -497,27 +493,6 @@ class HeapRegion: public G1OffsetTableContigSpace { _next_in_special_set = r; } - // True iff it is or has been an allocation region in the current - // collection pause. - bool is_gc_alloc_region() const { - return _is_gc_alloc_region; - } - void set_is_gc_alloc_region(bool b) { - _is_gc_alloc_region = b; - } - HeapRegion* next_gc_alloc_region() { - assert(is_gc_alloc_region(), "should only invoke on member of CS."); - assert(_next_in_special_set == NULL || - _next_in_special_set->is_gc_alloc_region(), - "Malformed CS."); - return _next_in_special_set; - } - void set_next_gc_alloc_region(HeapRegion* r) { - assert(is_gc_alloc_region(), "should only invoke on member of CS."); - assert(r == NULL || r->is_gc_alloc_region(), "Malformed CS."); - _next_in_special_set = r; - } - // Methods used by the HeapRegionSetBase class and subclasses. // Getter and setter for the next field used to link regions into diff --git a/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp b/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp index 0840bdd7aeb108080b228f9b7d39fc9a997d645c..8c5f15ea764bd1cd8e0fa93da4c5135fbfec8fb9 100644 --- a/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp +++ b/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp @@ -364,7 +364,10 @@ public: PosParPRT** next_addr() { return &_next; } bool should_expand(int tid) { - return par_tables() == NULL && tid > 0 && hr()->is_gc_alloc_region(); + // Given that we now defer RSet updates for after a GC we don't + // really need to expand the tables any more. This code should be + // cleaned up in the future (see CR 6921087). + return false; } void par_expand() {