7092309: G1: introduce old region set
Keep track of all the old regions in the heap with a heap region set. Reviewed-by: brutisso, johnc
This commit is contained in:
parent
b47310ebf8
commit
83958f54fb
@ -1518,6 +1518,7 @@ class G1NoteEndOfConcMarkClosure : public HeapRegionClosure {
|
||||
size_t _regions_claimed;
|
||||
size_t _freed_bytes;
|
||||
FreeRegionList* _local_cleanup_list;
|
||||
OldRegionSet* _old_proxy_set;
|
||||
HumongousRegionSet* _humongous_proxy_set;
|
||||
HRRSCleanupTask* _hrrs_cleanup_task;
|
||||
double _claimed_region_time;
|
||||
@ -1527,6 +1528,7 @@ public:
|
||||
G1NoteEndOfConcMarkClosure(G1CollectedHeap* g1,
|
||||
int worker_num,
|
||||
FreeRegionList* local_cleanup_list,
|
||||
OldRegionSet* old_proxy_set,
|
||||
HumongousRegionSet* humongous_proxy_set,
|
||||
HRRSCleanupTask* hrrs_cleanup_task);
|
||||
size_t freed_bytes() { return _freed_bytes; }
|
||||
@ -1557,9 +1559,11 @@ public:
|
||||
void work(int i) {
|
||||
double start = os::elapsedTime();
|
||||
FreeRegionList local_cleanup_list("Local Cleanup List");
|
||||
OldRegionSet old_proxy_set("Local Cleanup Old Proxy Set");
|
||||
HumongousRegionSet humongous_proxy_set("Local Cleanup Humongous Proxy Set");
|
||||
HRRSCleanupTask hrrs_cleanup_task;
|
||||
G1NoteEndOfConcMarkClosure g1_note_end(_g1h, i, &local_cleanup_list,
|
||||
&old_proxy_set,
|
||||
&humongous_proxy_set,
|
||||
&hrrs_cleanup_task);
|
||||
if (G1CollectedHeap::use_parallel_gc_threads()) {
|
||||
@ -1573,6 +1577,7 @@ public:
|
||||
// Now update the lists
|
||||
_g1h->update_sets_after_freeing_regions(g1_note_end.freed_bytes(),
|
||||
NULL /* free_list */,
|
||||
&old_proxy_set,
|
||||
&humongous_proxy_set,
|
||||
true /* par */);
|
||||
{
|
||||
@ -1643,6 +1648,7 @@ G1NoteEndOfConcMarkClosure::
|
||||
G1NoteEndOfConcMarkClosure(G1CollectedHeap* g1,
|
||||
int worker_num,
|
||||
FreeRegionList* local_cleanup_list,
|
||||
OldRegionSet* old_proxy_set,
|
||||
HumongousRegionSet* humongous_proxy_set,
|
||||
HRRSCleanupTask* hrrs_cleanup_task)
|
||||
: _g1(g1), _worker_num(worker_num),
|
||||
@ -1650,6 +1656,7 @@ G1NoteEndOfConcMarkClosure(G1CollectedHeap* g1,
|
||||
_freed_bytes(0),
|
||||
_claimed_region_time(0.0), _max_region_time(0.0),
|
||||
_local_cleanup_list(local_cleanup_list),
|
||||
_old_proxy_set(old_proxy_set),
|
||||
_humongous_proxy_set(humongous_proxy_set),
|
||||
_hrrs_cleanup_task(hrrs_cleanup_task) { }
|
||||
|
||||
@ -1665,6 +1672,7 @@ bool G1NoteEndOfConcMarkClosure::doHeapRegion(HeapRegion *hr) {
|
||||
_g1->free_region_if_empty(hr,
|
||||
&_freed_bytes,
|
||||
_local_cleanup_list,
|
||||
_old_proxy_set,
|
||||
_humongous_proxy_set,
|
||||
_hrrs_cleanup_task,
|
||||
true /* par */);
|
||||
@ -1689,6 +1697,7 @@ void ConcurrentMark::cleanup() {
|
||||
return;
|
||||
}
|
||||
|
||||
HRSPhaseSetter x(HRSPhaseCleanup);
|
||||
g1h->verify_region_sets_optional();
|
||||
|
||||
if (VerifyDuringGC) {
|
||||
|
@ -1203,6 +1203,7 @@ bool G1CollectedHeap::do_collection(bool explicit_gc,
|
||||
Universe::print_heap_before_gc();
|
||||
}
|
||||
|
||||
HRSPhaseSetter x(HRSPhaseFullGC);
|
||||
verify_region_sets_optional();
|
||||
|
||||
const bool do_clear_all_soft_refs = clear_all_soft_refs ||
|
||||
@ -1263,7 +1264,6 @@ bool G1CollectedHeap::do_collection(bool explicit_gc,
|
||||
release_mutator_alloc_region();
|
||||
abandon_gc_alloc_regions();
|
||||
g1_rem_set()->cleanupHRRS();
|
||||
tear_down_region_lists();
|
||||
|
||||
// We should call this after we retire any currently active alloc
|
||||
// regions so that all the ALLOC / RETIRE events are generated
|
||||
@ -1278,7 +1278,7 @@ bool G1CollectedHeap::do_collection(bool explicit_gc,
|
||||
g1_policy()->clear_incremental_cset();
|
||||
g1_policy()->stop_incremental_cset_building();
|
||||
|
||||
empty_young_list();
|
||||
tear_down_region_sets(false /* free_list_only */);
|
||||
g1_policy()->set_full_young_gcs(true);
|
||||
|
||||
// See the comments in g1CollectedHeap.hpp and
|
||||
@ -1301,9 +1301,7 @@ bool G1CollectedHeap::do_collection(bool explicit_gc,
|
||||
}
|
||||
|
||||
assert(free_regions() == 0, "we should not have added any free regions");
|
||||
rebuild_region_lists();
|
||||
|
||||
_summary_bytes_used = recalculate_used();
|
||||
rebuild_region_sets(false /* free_list_only */);
|
||||
|
||||
// Enqueue any discovered reference objects that have
|
||||
// not been removed from the discovered lists.
|
||||
@ -1764,9 +1762,9 @@ void G1CollectedHeap::shrink(size_t shrink_bytes) {
|
||||
// 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.
|
||||
tear_down_region_lists(); // We will rebuild them in a moment.
|
||||
tear_down_region_sets(true /* free_list_only */);
|
||||
shrink_helper(shrink_bytes);
|
||||
rebuild_region_lists();
|
||||
rebuild_region_sets(true /* free_list_only */);
|
||||
|
||||
_hrs.verify_optional();
|
||||
verify_region_sets_optional();
|
||||
@ -1799,6 +1797,7 @@ G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* policy_) :
|
||||
_full_collection(false),
|
||||
_free_list("Master Free List"),
|
||||
_secondary_free_list("Secondary Free List"),
|
||||
_old_set("Old Set"),
|
||||
_humongous_set("Master Humongous Set"),
|
||||
_free_regions_coming(false),
|
||||
_young_list(new YoungList(this)),
|
||||
@ -3352,6 +3351,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
|
||||
Universe::print_heap_before_gc();
|
||||
}
|
||||
|
||||
HRSPhaseSetter x(HRSPhaseEvacuation);
|
||||
verify_region_sets_optional();
|
||||
verify_dirty_young_regions();
|
||||
|
||||
@ -3774,6 +3774,11 @@ void G1CollectedHeap::init_gc_alloc_regions() {
|
||||
!retained_region->is_empty() &&
|
||||
!retained_region->isHumongous()) {
|
||||
retained_region->set_saved_mark();
|
||||
// The retained region was added to the old region set when it was
|
||||
// retired. We have to remove it now, since we don't allow regions
|
||||
// we allocate to in the region sets. We'll re-add it later, when
|
||||
// it's retired again.
|
||||
_old_set.remove(retained_region);
|
||||
_old_gc_alloc_region.set(retained_region);
|
||||
_hr_printer.reuse(retained_region);
|
||||
}
|
||||
@ -5338,6 +5343,7 @@ void G1CollectedHeap::evacuate_collection_set() {
|
||||
void G1CollectedHeap::free_region_if_empty(HeapRegion* hr,
|
||||
size_t* pre_used,
|
||||
FreeRegionList* free_list,
|
||||
OldRegionSet* old_proxy_set,
|
||||
HumongousRegionSet* humongous_proxy_set,
|
||||
HRRSCleanupTask* hrrs_cleanup_task,
|
||||
bool par) {
|
||||
@ -5346,6 +5352,7 @@ void G1CollectedHeap::free_region_if_empty(HeapRegion* hr,
|
||||
assert(hr->startsHumongous(), "we should only see starts humongous");
|
||||
free_humongous_region(hr, pre_used, free_list, humongous_proxy_set, par);
|
||||
} else {
|
||||
_old_set.remove_with_proxy(hr, old_proxy_set);
|
||||
free_region(hr, pre_used, free_list, par);
|
||||
}
|
||||
} else {
|
||||
@ -5402,6 +5409,7 @@ void G1CollectedHeap::free_humongous_region(HeapRegion* hr,
|
||||
|
||||
void G1CollectedHeap::update_sets_after_freeing_regions(size_t pre_used,
|
||||
FreeRegionList* free_list,
|
||||
OldRegionSet* old_proxy_set,
|
||||
HumongousRegionSet* humongous_proxy_set,
|
||||
bool par) {
|
||||
if (pre_used > 0) {
|
||||
@ -5417,6 +5425,10 @@ void G1CollectedHeap::update_sets_after_freeing_regions(size_t pre_used,
|
||||
MutexLockerEx x(FreeList_lock, Mutex::_no_safepoint_check_flag);
|
||||
_free_list.add_as_head(free_list);
|
||||
}
|
||||
if (old_proxy_set != NULL && !old_proxy_set->is_empty()) {
|
||||
MutexLockerEx x(OldSets_lock, Mutex::_no_safepoint_check_flag);
|
||||
_old_set.update_from_proxy(old_proxy_set);
|
||||
}
|
||||
if (humongous_proxy_set != NULL && !humongous_proxy_set->is_empty()) {
|
||||
MutexLockerEx x(OldSets_lock, Mutex::_no_safepoint_check_flag);
|
||||
_humongous_set.update_from_proxy(humongous_proxy_set);
|
||||
@ -5614,6 +5626,8 @@ void G1CollectedHeap::free_collection_set(HeapRegion* cs_head) {
|
||||
cur->set_young_index_in_cset(-1);
|
||||
cur->set_not_young();
|
||||
cur->set_evacuation_failed(false);
|
||||
// The region is now considered to be old.
|
||||
_old_set.add(cur);
|
||||
}
|
||||
cur = next;
|
||||
}
|
||||
@ -5629,6 +5643,7 @@ void G1CollectedHeap::free_collection_set(HeapRegion* cs_head) {
|
||||
young_time_ms += elapsed_ms;
|
||||
|
||||
update_sets_after_freeing_regions(pre_used, &local_free_list,
|
||||
NULL /* old_proxy_set */,
|
||||
NULL /* humongous_proxy_set */,
|
||||
false /* par */);
|
||||
policy->record_young_free_cset_time_ms(young_time_ms);
|
||||
@ -5740,52 +5755,106 @@ bool G1CollectedHeap::check_young_list_empty(bool check_heap, bool check_sample)
|
||||
return ret;
|
||||
}
|
||||
|
||||
void G1CollectedHeap::empty_young_list() {
|
||||
assert(heap_lock_held_for_gc(),
|
||||
"the heap lock should already be held by or for this thread");
|
||||
|
||||
_young_list->empty_list();
|
||||
}
|
||||
|
||||
// Done at the start of full GC.
|
||||
void G1CollectedHeap::tear_down_region_lists() {
|
||||
_free_list.remove_all();
|
||||
}
|
||||
|
||||
class RegionResetter: public HeapRegionClosure {
|
||||
G1CollectedHeap* _g1h;
|
||||
FreeRegionList _local_free_list;
|
||||
class TearDownRegionSetsClosure : public HeapRegionClosure {
|
||||
private:
|
||||
OldRegionSet *_old_set;
|
||||
|
||||
public:
|
||||
RegionResetter() : _g1h(G1CollectedHeap::heap()),
|
||||
_local_free_list("Local Free List for RegionResetter") { }
|
||||
TearDownRegionSetsClosure(OldRegionSet* old_set) : _old_set(old_set) { }
|
||||
|
||||
bool doHeapRegion(HeapRegion* r) {
|
||||
if (r->continuesHumongous()) return false;
|
||||
if (r->top() > r->bottom()) {
|
||||
if (r->top() < r->end()) {
|
||||
Copy::fill_to_words(r->top(),
|
||||
pointer_delta(r->end(), r->top()));
|
||||
}
|
||||
if (r->is_empty()) {
|
||||
// We ignore empty regions, we'll empty the free list afterwards
|
||||
} else if (r->is_young()) {
|
||||
// We ignore young regions, we'll empty the young list afterwards
|
||||
} else if (r->isHumongous()) {
|
||||
// We ignore humongous regions, we're not tearing down the
|
||||
// humongous region set
|
||||
} else {
|
||||
assert(r->is_empty(), "tautology");
|
||||
_local_free_list.add_as_tail(r);
|
||||
// The rest should be old
|
||||
_old_set->remove(r);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void update_free_lists() {
|
||||
_g1h->update_sets_after_freeing_regions(0, &_local_free_list, NULL,
|
||||
false /* par */);
|
||||
~TearDownRegionSetsClosure() {
|
||||
assert(_old_set->is_empty(), "post-condition");
|
||||
}
|
||||
};
|
||||
|
||||
// Done at the end of full GC.
|
||||
void G1CollectedHeap::rebuild_region_lists() {
|
||||
// This needs to go at the end of the full GC.
|
||||
RegionResetter rs;
|
||||
heap_region_iterate(&rs);
|
||||
rs.update_free_lists();
|
||||
void G1CollectedHeap::tear_down_region_sets(bool free_list_only) {
|
||||
assert_at_safepoint(true /* should_be_vm_thread */);
|
||||
|
||||
if (!free_list_only) {
|
||||
TearDownRegionSetsClosure cl(&_old_set);
|
||||
heap_region_iterate(&cl);
|
||||
|
||||
// Need to do this after the heap iteration to be able to
|
||||
// recognize the young regions and ignore them during the iteration.
|
||||
_young_list->empty_list();
|
||||
}
|
||||
_free_list.remove_all();
|
||||
}
|
||||
|
||||
class RebuildRegionSetsClosure : public HeapRegionClosure {
|
||||
private:
|
||||
bool _free_list_only;
|
||||
OldRegionSet* _old_set;
|
||||
FreeRegionList* _free_list;
|
||||
size_t _total_used;
|
||||
|
||||
public:
|
||||
RebuildRegionSetsClosure(bool free_list_only,
|
||||
OldRegionSet* old_set, FreeRegionList* free_list) :
|
||||
_free_list_only(free_list_only),
|
||||
_old_set(old_set), _free_list(free_list), _total_used(0) {
|
||||
assert(_free_list->is_empty(), "pre-condition");
|
||||
if (!free_list_only) {
|
||||
assert(_old_set->is_empty(), "pre-condition");
|
||||
}
|
||||
}
|
||||
|
||||
bool doHeapRegion(HeapRegion* r) {
|
||||
if (r->continuesHumongous()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (r->is_empty()) {
|
||||
// Add free regions to the free list
|
||||
_free_list->add_as_tail(r);
|
||||
} else if (!_free_list_only) {
|
||||
assert(!r->is_young(), "we should not come across young regions");
|
||||
|
||||
if (r->isHumongous()) {
|
||||
// We ignore humongous regions, we left the humongous set unchanged
|
||||
} else {
|
||||
// The rest should be old, add them to the old set
|
||||
_old_set->add(r);
|
||||
}
|
||||
_total_used += r->used();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t total_used() {
|
||||
return _total_used;
|
||||
}
|
||||
};
|
||||
|
||||
void G1CollectedHeap::rebuild_region_sets(bool free_list_only) {
|
||||
assert_at_safepoint(true /* should_be_vm_thread */);
|
||||
|
||||
RebuildRegionSetsClosure cl(free_list_only, &_old_set, &_free_list);
|
||||
heap_region_iterate(&cl);
|
||||
|
||||
if (!free_list_only) {
|
||||
_summary_bytes_used = cl.total_used();
|
||||
}
|
||||
assert(_summary_bytes_used == recalculate_used(),
|
||||
err_msg("inconsistent _summary_bytes_used, "
|
||||
"value: "SIZE_FORMAT" recalculated: "SIZE_FORMAT,
|
||||
_summary_bytes_used, recalculate_used()));
|
||||
}
|
||||
|
||||
void G1CollectedHeap::set_refine_cte_cl_concurrency(bool concurrent) {
|
||||
@ -5882,6 +5951,8 @@ void G1CollectedHeap::retire_gc_alloc_region(HeapRegion* alloc_region,
|
||||
g1_policy()->record_bytes_copied_during_gc(allocated_bytes);
|
||||
if (ap == GCAllocForSurvived) {
|
||||
young_list()->add_survivor_region(alloc_region);
|
||||
} else {
|
||||
_old_set.add(alloc_region);
|
||||
}
|
||||
_hr_printer.retire(alloc_region);
|
||||
}
|
||||
@ -5913,15 +5984,17 @@ void OldGCAllocRegion::retire_region(HeapRegion* alloc_region,
|
||||
|
||||
class VerifyRegionListsClosure : public HeapRegionClosure {
|
||||
private:
|
||||
HumongousRegionSet* _humongous_set;
|
||||
FreeRegionList* _free_list;
|
||||
OldRegionSet* _old_set;
|
||||
HumongousRegionSet* _humongous_set;
|
||||
size_t _region_count;
|
||||
|
||||
public:
|
||||
VerifyRegionListsClosure(HumongousRegionSet* humongous_set,
|
||||
VerifyRegionListsClosure(OldRegionSet* old_set,
|
||||
HumongousRegionSet* humongous_set,
|
||||
FreeRegionList* free_list) :
|
||||
_humongous_set(humongous_set), _free_list(free_list),
|
||||
_region_count(0) { }
|
||||
_old_set(old_set), _humongous_set(humongous_set),
|
||||
_free_list(free_list), _region_count(0) { }
|
||||
|
||||
size_t region_count() { return _region_count; }
|
||||
|
||||
@ -5938,6 +6011,8 @@ public:
|
||||
_humongous_set->verify_next_region(hr);
|
||||
} else if (hr->is_empty()) {
|
||||
_free_list->verify_next_region(hr);
|
||||
} else {
|
||||
_old_set->verify_next_region(hr);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -5964,6 +6039,7 @@ void G1CollectedHeap::verify_region_sets() {
|
||||
MutexLockerEx x(SecondaryFreeList_lock, Mutex::_no_safepoint_check_flag);
|
||||
_secondary_free_list.verify();
|
||||
}
|
||||
_old_set.verify();
|
||||
_humongous_set.verify();
|
||||
|
||||
// If a concurrent region freeing operation is in progress it will
|
||||
@ -5987,12 +6063,14 @@ void G1CollectedHeap::verify_region_sets() {
|
||||
|
||||
// Finally, make sure that the region accounting in the lists is
|
||||
// consistent with what we see in the heap.
|
||||
_old_set.verify_start();
|
||||
_humongous_set.verify_start();
|
||||
_free_list.verify_start();
|
||||
|
||||
VerifyRegionListsClosure cl(&_humongous_set, &_free_list);
|
||||
VerifyRegionListsClosure cl(&_old_set, &_humongous_set, &_free_list);
|
||||
heap_region_iterate(&cl);
|
||||
|
||||
_old_set.verify_end();
|
||||
_humongous_set.verify_end();
|
||||
_free_list.verify_end();
|
||||
}
|
||||
|
@ -239,6 +239,9 @@ private:
|
||||
// master free list when appropriate.
|
||||
SecondaryFreeRegionList _secondary_free_list;
|
||||
|
||||
// It keeps track of the old regions.
|
||||
MasterOldRegionSet _old_set;
|
||||
|
||||
// It keeps track of the humongous regions.
|
||||
MasterHumongousRegionSet _humongous_set;
|
||||
|
||||
@ -248,10 +251,21 @@ private:
|
||||
// The block offset table for the G1 heap.
|
||||
G1BlockOffsetSharedArray* _bot_shared;
|
||||
|
||||
// Move all of the regions off the free lists, then rebuild those free
|
||||
// lists, before and after full GC.
|
||||
void tear_down_region_lists();
|
||||
void rebuild_region_lists();
|
||||
// Tears down the region sets / lists so that they are empty and the
|
||||
// regions on the heap do not belong to a region set / list. The
|
||||
// only exception is the humongous set which we leave unaltered. If
|
||||
// free_list_only is true, it will only tear down the master free
|
||||
// list. It is called before a Full GC (free_list_only == false) or
|
||||
// before heap shrinking (free_list_only == true).
|
||||
void tear_down_region_sets(bool free_list_only);
|
||||
|
||||
// Rebuilds the region sets / lists so that they are repopulated to
|
||||
// reflect the contents of the heap. The only exception is the
|
||||
// humongous set which was not torn down in the first place. If
|
||||
// free_list_only is true, it will only rebuild the master free
|
||||
// list. It is called after a Full GC (free_list_only == false) or
|
||||
// after heap shrinking (free_list_only == true).
|
||||
void rebuild_region_sets(bool free_list_only);
|
||||
|
||||
// The sequence of all heap regions in the heap.
|
||||
HeapRegionSeq _hrs;
|
||||
@ -1124,6 +1138,10 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void old_set_remove(HeapRegion* hr) {
|
||||
_old_set.remove(hr);
|
||||
}
|
||||
|
||||
void set_free_regions_coming();
|
||||
void reset_free_regions_coming();
|
||||
bool free_regions_coming() { return _free_regions_coming; }
|
||||
@ -1153,6 +1171,7 @@ public:
|
||||
void free_region_if_empty(HeapRegion* hr,
|
||||
size_t* pre_used,
|
||||
FreeRegionList* free_list,
|
||||
OldRegionSet* old_proxy_set,
|
||||
HumongousRegionSet* humongous_proxy_set,
|
||||
HRRSCleanupTask* hrrs_cleanup_task,
|
||||
bool par);
|
||||
@ -1163,6 +1182,7 @@ public:
|
||||
// (if par is true, it will do so by taking the ParGCRareEvent_lock).
|
||||
void update_sets_after_freeing_regions(size_t pre_used,
|
||||
FreeRegionList* free_list,
|
||||
OldRegionSet* old_proxy_set,
|
||||
HumongousRegionSet* humongous_proxy_set,
|
||||
bool par);
|
||||
|
||||
@ -1452,8 +1472,6 @@ public:
|
||||
// asserted to be this type.
|
||||
static G1CollectedHeap* heap();
|
||||
|
||||
void empty_young_list();
|
||||
|
||||
void set_region_short_lived_locked(HeapRegion* hr);
|
||||
// add appropriate methods for any other surv rate groups
|
||||
|
||||
|
@ -3015,6 +3015,7 @@ void G1CollectorPolicy::choose_collection_set(double target_pause_time_ms) {
|
||||
hr = _collectionSetChooser->getNextMarkedRegion(time_remaining_ms,
|
||||
avg_prediction);
|
||||
if (hr != NULL) {
|
||||
_g1->old_set_remove(hr);
|
||||
double predicted_time_ms = predict_region_elapsed_time_ms(hr, false);
|
||||
time_remaining_ms -= predicted_time_ms;
|
||||
predicted_pause_time_ms += predicted_time_ms;
|
||||
|
@ -236,6 +236,7 @@ public:
|
||||
// at the end of the GC, so no point in updating those values here.
|
||||
_g1h->update_sets_after_freeing_regions(0, /* pre_used */
|
||||
NULL, /* free_list */
|
||||
NULL, /* old_proxy_set */
|
||||
&_humongous_proxy_set,
|
||||
false /* par */);
|
||||
}
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "gc_implementation/g1/heapRegionSet.inline.hpp"
|
||||
|
||||
size_t HeapRegionSetBase::_unrealistically_long_length = 0;
|
||||
HRSPhase HeapRegionSetBase::_phase = HRSPhaseNone;
|
||||
|
||||
//////////////////// HeapRegionSetBase ////////////////////
|
||||
|
||||
@ -192,6 +193,17 @@ void HeapRegionSetBase::verify_end() {
|
||||
_verify_in_progress = false;
|
||||
}
|
||||
|
||||
void HeapRegionSetBase::clear_phase() {
|
||||
assert(_phase != HRSPhaseNone, "pre-condition");
|
||||
_phase = HRSPhaseNone;
|
||||
}
|
||||
|
||||
void HeapRegionSetBase::set_phase(HRSPhase phase) {
|
||||
assert(_phase == HRSPhaseNone, "pre-condition");
|
||||
assert(phase != HRSPhaseNone, "pre-condition");
|
||||
_phase = phase;
|
||||
}
|
||||
|
||||
void HeapRegionSetBase::print_on(outputStream* out, bool print_contents) {
|
||||
out->cr();
|
||||
out->print_cr("Set: %s ("PTR_FORMAT")", name(), this);
|
||||
|
@ -47,8 +47,18 @@ typedef FormatBuffer<HRS_ERR_MSG_BUFSZ> hrs_err_msg;
|
||||
|
||||
class hrs_ext_msg;
|
||||
|
||||
typedef enum {
|
||||
HRSPhaseNone,
|
||||
HRSPhaseEvacuation,
|
||||
HRSPhaseCleanup,
|
||||
HRSPhaseFullGC
|
||||
} HRSPhase;
|
||||
|
||||
class HRSPhaseSetter;
|
||||
|
||||
class HeapRegionSetBase VALUE_OBJ_CLASS_SPEC {
|
||||
friend class hrs_ext_msg;
|
||||
friend class HRSPhaseSetter;
|
||||
|
||||
protected:
|
||||
static size_t calculate_region_num(HeapRegion* hr);
|
||||
@ -80,6 +90,15 @@ protected:
|
||||
size_t _calc_total_capacity_bytes;
|
||||
size_t _calc_total_used_bytes;
|
||||
|
||||
// This is here so that it can be used in the subclasses to assert
|
||||
// something different depending on which phase the GC is in. This
|
||||
// can be particularly helpful in the check_mt_safety() methods.
|
||||
static HRSPhase _phase;
|
||||
|
||||
// Only used by HRSPhaseSetter.
|
||||
static void clear_phase();
|
||||
static void set_phase(HRSPhase phase);
|
||||
|
||||
// verify_region() is used to ensure that the contents of a region
|
||||
// added to / removed from a set are consistent. Different sets
|
||||
// make different assumptions about the regions added to them. So
|
||||
@ -177,6 +196,16 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class HRSPhaseSetter {
|
||||
public:
|
||||
HRSPhaseSetter(HRSPhase phase) {
|
||||
HeapRegionSetBase::set_phase(phase);
|
||||
}
|
||||
~HRSPhaseSetter() {
|
||||
HeapRegionSetBase::clear_phase();
|
||||
}
|
||||
};
|
||||
|
||||
// These two macros are provided for convenience, to keep the uses of
|
||||
// these two asserts a bit more concise.
|
||||
|
||||
|
@ -26,6 +26,17 @@
|
||||
#include "gc_implementation/g1/heapRegionRemSet.hpp"
|
||||
#include "gc_implementation/g1/heapRegionSets.hpp"
|
||||
|
||||
// Note on the check_mt_safety() methods below:
|
||||
//
|
||||
// Verification of the "master" heap region sets / lists that are
|
||||
// maintained by G1CollectedHeap is always done during a STW pause and
|
||||
// by the VM thread at the start / end of the pause. The standard
|
||||
// verification methods all assert check_mt_safety(). This is
|
||||
// important as it ensures that verification is done without
|
||||
// concurrent updates taking place at the same time. It follows, that,
|
||||
// for the "master" heap region sets / lists, the check_mt_safety()
|
||||
// method should include the VM thread / STW case.
|
||||
|
||||
//////////////////// FreeRegionList ////////////////////
|
||||
|
||||
const char* FreeRegionList::verify_region_extra(HeapRegion* hr) {
|
||||
@ -33,7 +44,7 @@ const char* FreeRegionList::verify_region_extra(HeapRegion* hr) {
|
||||
return "the region should not be young";
|
||||
}
|
||||
// The superclass will check that the region is empty and
|
||||
// not-humongous.
|
||||
// not humongous.
|
||||
return HeapRegionLinkedList::verify_region_extra(hr);
|
||||
}
|
||||
|
||||
@ -58,12 +69,16 @@ bool MasterFreeRegionList::check_mt_safety() {
|
||||
// (b) If we're not at a safepoint, operations on the master free
|
||||
// list should be invoked while holding the Heap_lock.
|
||||
|
||||
guarantee((SafepointSynchronize::is_at_safepoint() &&
|
||||
(Thread::current()->is_VM_thread() ||
|
||||
FreeList_lock->owned_by_self())) ||
|
||||
(!SafepointSynchronize::is_at_safepoint() &&
|
||||
Heap_lock->owned_by_self()),
|
||||
hrs_ext_msg(this, "master free list MT safety protocol"));
|
||||
if (SafepointSynchronize::is_at_safepoint()) {
|
||||
guarantee(Thread::current()->is_VM_thread() ||
|
||||
FreeList_lock->owned_by_self(),
|
||||
hrs_ext_msg(this, "master free list MT safety protocol "
|
||||
"at a safepoint"));
|
||||
} else {
|
||||
guarantee(Heap_lock->owned_by_self(),
|
||||
hrs_ext_msg(this, "master free list MT safety protocol "
|
||||
"outside a safepoint"));
|
||||
}
|
||||
|
||||
return FreeRegionList::check_mt_safety();
|
||||
}
|
||||
@ -81,6 +96,48 @@ bool SecondaryFreeRegionList::check_mt_safety() {
|
||||
return FreeRegionList::check_mt_safety();
|
||||
}
|
||||
|
||||
//////////////////// OldRegionSet ////////////////////
|
||||
|
||||
const char* OldRegionSet::verify_region_extra(HeapRegion* hr) {
|
||||
if (hr->is_young()) {
|
||||
return "the region should not be young";
|
||||
}
|
||||
// The superclass will check that the region is not empty and not
|
||||
// humongous.
|
||||
return HeapRegionSet::verify_region_extra(hr);
|
||||
}
|
||||
|
||||
//////////////////// MasterOldRegionSet ////////////////////
|
||||
|
||||
bool MasterOldRegionSet::check_mt_safety() {
|
||||
// Master Old Set MT safety protocol:
|
||||
// (a) If we're at a safepoint, operations on the master old set
|
||||
// should be invoked:
|
||||
// - by the VM thread (which will serialize them), or
|
||||
// - by the GC workers while holding the FreeList_lock, if we're
|
||||
// at a safepoint for an evacuation pause (this lock is taken
|
||||
// anyway when an GC alloc region is retired so that a new one
|
||||
// is allocated from the free list), or
|
||||
// - by the GC workers while holding the OldSets_lock, if we're at a
|
||||
// safepoint for a cleanup pause.
|
||||
// (b) If we're not at a safepoint, operations on the master old set
|
||||
// should be invoked while holding the Heap_lock.
|
||||
|
||||
if (SafepointSynchronize::is_at_safepoint()) {
|
||||
guarantee(Thread::current()->is_VM_thread() ||
|
||||
_phase == HRSPhaseEvacuation && FreeList_lock->owned_by_self() ||
|
||||
_phase == HRSPhaseCleanup && OldSets_lock->owned_by_self(),
|
||||
hrs_ext_msg(this, "master old set MT safety protocol "
|
||||
"at a safepoint"));
|
||||
} else {
|
||||
guarantee(Heap_lock->owned_by_self(),
|
||||
hrs_ext_msg(this, "master old set MT safety protocol "
|
||||
"outside a safepoint"));
|
||||
}
|
||||
|
||||
return OldRegionSet::check_mt_safety();
|
||||
}
|
||||
|
||||
//////////////////// HumongousRegionSet ////////////////////
|
||||
|
||||
const char* HumongousRegionSet::verify_region_extra(HeapRegion* hr) {
|
||||
@ -103,11 +160,16 @@ bool MasterHumongousRegionSet::check_mt_safety() {
|
||||
// (b) If we're not at a safepoint, operations on the master
|
||||
// humongous set should be invoked while holding the Heap_lock.
|
||||
|
||||
guarantee((SafepointSynchronize::is_at_safepoint() &&
|
||||
(Thread::current()->is_VM_thread() ||
|
||||
OldSets_lock->owned_by_self())) ||
|
||||
(!SafepointSynchronize::is_at_safepoint() &&
|
||||
Heap_lock->owned_by_self()),
|
||||
hrs_ext_msg(this, "master humongous set MT safety protocol"));
|
||||
if (SafepointSynchronize::is_at_safepoint()) {
|
||||
guarantee(Thread::current()->is_VM_thread() ||
|
||||
OldSets_lock->owned_by_self(),
|
||||
hrs_ext_msg(this, "master humongous set MT safety protocol "
|
||||
"at a safepoint"));
|
||||
} else {
|
||||
guarantee(Heap_lock->owned_by_self(),
|
||||
hrs_ext_msg(this, "master humongous set MT safety protocol "
|
||||
"outside a safepoint"));
|
||||
}
|
||||
|
||||
return HumongousRegionSet::check_mt_safety();
|
||||
}
|
||||
|
@ -61,6 +61,30 @@ public:
|
||||
SecondaryFreeRegionList(const char* name) : FreeRegionList(name) { }
|
||||
};
|
||||
|
||||
//////////////////// OldRegionSet ////////////////////
|
||||
|
||||
class OldRegionSet : public HeapRegionSet {
|
||||
protected:
|
||||
virtual const char* verify_region_extra(HeapRegion* hr);
|
||||
|
||||
virtual bool regions_humongous() { return false; }
|
||||
virtual bool regions_empty() { return false; }
|
||||
|
||||
public:
|
||||
OldRegionSet(const char* name) : HeapRegionSet(name) { }
|
||||
};
|
||||
|
||||
//////////////////// MasterOldRegionSet ////////////////////
|
||||
|
||||
class MasterOldRegionSet : public OldRegionSet {
|
||||
private:
|
||||
protected:
|
||||
virtual bool check_mt_safety();
|
||||
|
||||
public:
|
||||
MasterOldRegionSet(const char* name) : OldRegionSet(name) { }
|
||||
};
|
||||
|
||||
//////////////////// HumongousRegionSet ////////////////////
|
||||
|
||||
class HumongousRegionSet : public HeapRegionSet {
|
||||
|
Loading…
Reference in New Issue
Block a user