8071913: Filter out entries to free/uncommitted regions during iteration

Reviewed-by: sjohanss, kbarrett
This commit is contained in:
Thomas Schatzl 2018-10-31 13:43:57 +01:00
parent adb1dcdcc2
commit 3a343a5681
7 changed files with 87 additions and 31 deletions

@ -1120,6 +1120,7 @@ public:
// Return the region with the given index. It assumes the index is valid.
inline HeapRegion* region_at(uint index) const;
inline HeapRegion* region_at_or_null(uint index) const;
// Return the next region (by index) that is part of the same
// humongous object that hr is part of.
@ -1157,6 +1158,11 @@ public:
template <class T>
inline HeapRegion* heap_region_containing(const T addr) const;
// Returns the HeapRegion that contains addr, or NULL if that is an uncommitted
// region. addr must not be NULL.
template <class T>
inline HeapRegion* heap_region_containing_or_null(const T addr) const;
// A CollectedHeap is divided into a dense sequence of "blocks"; that is,
// each address in the (reserved) heap is a member of exactly
// one block. The defining characteristic of a block is that it is

@ -60,6 +60,9 @@ size_t G1CollectedHeap::desired_plab_sz(InCSetState dest) {
// Return the region with the given index. It assumes the index is valid.
inline HeapRegion* G1CollectedHeap::region_at(uint index) const { return _hrm.at(index); }
// Return the region with the given index, or NULL if unmapped. It assumes the index is valid.
inline HeapRegion* G1CollectedHeap::region_at_or_null(uint index) const { return _hrm.at_or_null(index); }
inline HeapRegion* G1CollectedHeap::next_region_in_humongous(HeapRegion* hr) const {
return _hrm.next_region_in_humongous(hr);
}
@ -84,6 +87,16 @@ inline HeapRegion* G1CollectedHeap::heap_region_containing(const T addr) const {
return _hrm.addr_to_region((HeapWord*) addr);
}
template <class T>
inline HeapRegion* G1CollectedHeap::heap_region_containing_or_null(const T addr) const {
assert(addr != NULL, "invariant");
assert(is_in_g1_reserved((const void*) addr),
"Address " PTR_FORMAT " is outside of the heap ranging from [" PTR_FORMAT " to " PTR_FORMAT ")",
p2i((void*)addr), p2i(g1_reserved().start()), p2i(g1_reserved().end()));
uint const region_idx = addr_to_region(addr);
return region_at_or_null(region_idx);
}
inline void G1CollectedHeap::old_set_add(HeapRegion* hr) {
_old_set.add(hr);
}

@ -133,10 +133,10 @@ private:
virtual bool do_heap_region(HeapRegion* r) {
uint hrm_index = r->hrm_index();
if (!r->in_collection_set() && r->is_old_or_humongous_or_archive()) {
if (!r->in_collection_set() && r->is_old_or_humongous_or_archive() && !r->is_empty()) {
_scan_top[hrm_index] = r->top();
} else {
_scan_top[hrm_index] = r->bottom();
_scan_top[hrm_index] = NULL;
}
return false;
}
@ -191,6 +191,7 @@ public:
void reset() {
for (uint i = 0; i < _max_regions; i++) {
_iter_states[i] = Unclaimed;
_scan_top[i] = NULL;
}
G1ResetScanTopClosure cl(_scan_top);
@ -350,6 +351,10 @@ void G1ScanRSForRegionClosure::scan_rem_set_roots(HeapRegion* r) {
_scan_state->add_dirty_region(region_idx);
}
if (r->rem_set()->cardset_is_empty()) {
return;
}
// We claim cards in blocks so as to reduce the contention.
size_t const block_size = G1RSetScanBlockSize;
@ -367,18 +372,21 @@ void G1ScanRSForRegionClosure::scan_rem_set_roots(HeapRegion* r) {
}
_cards_claimed++;
// If the card is dirty, then G1 will scan it during Update RS.
if (_ct->is_card_claimed(card_index) || _ct->is_card_dirty(card_index)) {
HeapWord* const card_start = _g1h->bot()->address_for_index_raw(card_index);
uint const region_idx_for_card = _g1h->addr_to_region(card_start);
#ifdef ASSERT
HeapRegion* hr = _g1h->region_at_or_null(region_idx_for_card);
assert(hr == NULL || hr->is_in_reserved(card_start),
"Card start " PTR_FORMAT " to scan outside of region %u", p2i(card_start), _g1h->region_at(region_idx_for_card)->hrm_index());
#endif
HeapWord* const top = _scan_state->scan_top(region_idx_for_card);
if (card_start >= top) {
continue;
}
HeapWord* const card_start = _g1h->bot()->address_for_index(card_index);
uint const region_idx_for_card = _g1h->addr_to_region(card_start);
assert(_g1h->region_at(region_idx_for_card)->is_in_reserved(card_start),
"Card start " PTR_FORMAT " to scan outside of region %u", p2i(card_start), _g1h->region_at(region_idx_for_card)->hrm_index());
HeapWord* const top = _scan_state->scan_top(region_idx_for_card);
if (card_start >= top) {
// If the card is dirty, then G1 will scan it during Update RS.
if (_ct->is_card_claimed(card_index) || _ct->is_card_dirty(card_index)) {
continue;
}
@ -545,6 +553,16 @@ void G1RemSet::refine_card_concurrently(jbyte* card_ptr,
uint worker_i) {
assert(!_g1h->is_gc_active(), "Only call concurrently");
// Construct the region representing the card.
HeapWord* start = _ct->addr_for(card_ptr);
// And find the region containing it.
HeapRegion* r = _g1h->heap_region_containing_or_null(start);
// If this is a (stale) card into an uncommitted region, exit.
if (r == NULL) {
return;
}
check_card_ptr(card_ptr, _ct);
// If the card is no longer dirty, nothing to do.
@ -552,11 +570,6 @@ void G1RemSet::refine_card_concurrently(jbyte* card_ptr,
return;
}
// Construct the region representing the card.
HeapWord* start = _ct->addr_for(card_ptr);
// And find the region containing it.
HeapRegion* r = _g1h->heap_region_containing(start);
// This check is needed for some uncommon cases where we should
// ignore the card.
//
@ -679,6 +692,18 @@ bool G1RemSet::refine_card_during_gc(jbyte* card_ptr,
G1ScanObjsDuringUpdateRSClosure* update_rs_cl) {
assert(_g1h->is_gc_active(), "Only call during GC");
// Construct the region representing the card.
HeapWord* card_start = _ct->addr_for(card_ptr);
// And find the region containing it.
uint const card_region_idx = _g1h->addr_to_region(card_start);
HeapWord* scan_limit = _scan_state->scan_top(card_region_idx);
if (scan_limit == NULL) {
// This is a card into an uncommitted region. We need to bail out early as we
// should not access the corresponding card table entry.
return false;
}
check_card_ptr(card_ptr, _ct);
// If the card is no longer dirty, nothing to do. This covers cards that were already
@ -691,13 +716,7 @@ bool G1RemSet::refine_card_during_gc(jbyte* card_ptr,
// number of potential duplicate scans (multiple threads may enqueue the same card twice).
*card_ptr = G1CardTable::clean_card_val() | G1CardTable::claimed_card_val();
// Construct the region representing the card.
HeapWord* card_start = _ct->addr_for(card_ptr);
// And find the region containing it.
uint const card_region_idx = _g1h->addr_to_region(card_start);
_scan_state->add_dirty_region(card_region_idx);
HeapWord* scan_limit = _scan_state->scan_top(card_region_idx);
if (scan_limit <= card_start) {
// If the card starts above the area in the region containing objects to scan, skip it.
return false;

@ -123,10 +123,7 @@ class HeapRegionManager: public CHeapObj<mtGC> {
public:
bool is_free(HeapRegion* hr) const;
#endif
// Returns whether the given region is available for allocation.
bool is_available(uint region) const;
public:
public:
// Empty constructor, we'll initialize it with the initialize() method.
HeapRegionManager();
@ -147,6 +144,13 @@ public:
// is valid.
inline HeapRegion* at(uint index) const;
// Return the HeapRegion at the given index, NULL if the index
// is for an unavailable region.
inline HeapRegion* at_or_null(uint index) const;
// Returns whether the given region is available for allocation.
bool is_available(uint region) const;
// Return the next region (by index) that is part of the same
// humongous object that hr is part of.
inline HeapRegion* next_region_in_humongous(HeapRegion* hr) const;

@ -47,6 +47,16 @@ inline HeapRegion* HeapRegionManager::at(uint index) const {
return hr;
}
inline HeapRegion* HeapRegionManager::at_or_null(uint index) const {
if (!is_available(index)) {
return NULL;
}
HeapRegion* hr = _regions.get_by_index(index);
assert(hr != NULL, "All available regions must have a HeapRegion but index %u has not.", index);
assert(hr->hrm_index() == index, "sanity");
return hr;
}
inline HeapRegion* HeapRegionManager::next_region_in_humongous(HeapRegion* hr) const {
uint index = hr->hrm_index();
assert(is_available(index), "pre-condition");

@ -751,7 +751,7 @@ bool HeapRegionRemSetIterator::coarse_has_next(size_t& card_index) {
_coarse_cur_region_cur_card = 0;
HeapWord* r_bot =
_g1h->region_at((uint) _coarse_cur_region_index)->bottom();
_cur_region_card_offset = _bot->index_for(r_bot);
_cur_region_card_offset = _bot->index_for_raw(r_bot);
} else {
return false;
}
@ -792,7 +792,7 @@ void HeapRegionRemSetIterator::switch_to_prt(PerRegionTable* prt) {
_fine_cur_prt = prt;
HeapWord* r_bot = _fine_cur_prt->hr()->bottom();
_cur_region_card_offset = _bot->index_for(r_bot);
_cur_region_card_offset = _bot->index_for_raw(r_bot);
// The bitmap scan for the PRT always scans from _cur_region_cur_card + 1.
// To avoid special-casing this start case, and not miss the first bitmap

@ -187,8 +187,12 @@ public:
static void setup_remset_size();
bool cardset_is_empty() const {
return _other_regions.is_empty();
}
bool is_empty() const {
return (strong_code_roots_list_length() == 0) && _other_regions.is_empty();
return (strong_code_roots_list_length() == 0) && cardset_is_empty();
}
bool occupancy_less_or_equal_than(size_t occ) const {
@ -353,7 +357,7 @@ public:
};
class HeapRegionRemSetIterator : public StackObj {
private:
private:
// The region RSet over which we are iterating.
HeapRegionRemSet* _hrrs;
@ -401,7 +405,7 @@ class HeapRegionRemSetIterator : public StackObj {
// The Sparse remembered set iterator.
SparsePRTIter _sparse_iter;
public:
public:
HeapRegionRemSetIterator(HeapRegionRemSet* hrrs);
// If there remains one or more cards to be yielded, returns true and