mirror of
https://github.com/openjdk/jdk.git
synced 2026-04-14 08:58:46 +00:00
8380958: GenShen: Regulator thread may observe inconsistent old generation state
Reviewed-by: kdnilsen, xpeng
This commit is contained in:
parent
410b3e816a
commit
e254526f4a
@ -576,7 +576,7 @@ void ShenandoahOldHeuristics::prepare_for_old_collections() {
|
||||
} else if (has_coalesce_and_fill_candidates()) {
|
||||
_old_generation->transition_to(ShenandoahOldGeneration::FILLING);
|
||||
} else {
|
||||
_old_generation->transition_to(ShenandoahOldGeneration::WAITING_FOR_BOOTSTRAP);
|
||||
_old_generation->transition_to(ShenandoahOldGeneration::IDLE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -55,7 +55,7 @@ bool ShenandoahDegenGC::collect(GCCause::Cause cause) {
|
||||
vmop_degenerated();
|
||||
ShenandoahHeap* heap = ShenandoahHeap::heap();
|
||||
if (heap->mode()->is_generational()) {
|
||||
bool is_bootstrap_gc = heap->old_generation()->is_bootstrapping();
|
||||
bool is_bootstrap_gc = heap->young_generation()->is_bootstrap_cycle();
|
||||
heap->mmu_tracker()->record_degenerated(GCId::current(), is_bootstrap_gc);
|
||||
const char* msg = is_bootstrap_gc? "At end of Degenerated Bootstrap Old GC": "At end of Degenerated Young GC";
|
||||
heap->log_heap_status(msg);
|
||||
|
||||
@ -422,12 +422,11 @@ void ShenandoahGenerationalControlThread::service_concurrent_old_cycle(const She
|
||||
}
|
||||
|
||||
// Coalescing threads completed and nothing was cancelled. it is safe to transition from this state.
|
||||
old_generation->transition_to(ShenandoahOldGeneration::WAITING_FOR_BOOTSTRAP);
|
||||
old_generation->transition_to(ShenandoahOldGeneration::IDLE);
|
||||
return;
|
||||
}
|
||||
case ShenandoahOldGeneration::WAITING_FOR_BOOTSTRAP:
|
||||
old_generation->transition_to(ShenandoahOldGeneration::BOOTSTRAPPING);
|
||||
case ShenandoahOldGeneration::BOOTSTRAPPING: {
|
||||
case ShenandoahOldGeneration::IDLE:
|
||||
old_generation->transition_to(ShenandoahOldGeneration::MARKING);
|
||||
// Configure the young generation's concurrent mark to put objects in
|
||||
// old regions into the concurrent mark queues associated with the old
|
||||
// generation. The young cycle will run as normal except that rather than
|
||||
@ -450,8 +449,6 @@ void ShenandoahGenerationalControlThread::service_concurrent_old_cycle(const She
|
||||
// and init mark for the concurrent mark. All of that work will have been
|
||||
// done by the bootstrapping young cycle.
|
||||
set_gc_mode(servicing_old);
|
||||
old_generation->transition_to(ShenandoahOldGeneration::MARKING);
|
||||
}
|
||||
case ShenandoahOldGeneration::MARKING: {
|
||||
ShenandoahGCSession session(request.cause, old_generation);
|
||||
bool marking_complete = resume_concurrent_old_cycle(old_generation, request.cause);
|
||||
@ -644,12 +641,6 @@ void ShenandoahGenerationalControlThread::service_stw_degenerated_cycle(const Sh
|
||||
if (request.generation->is_global()) {
|
||||
assert(_heap->old_generation()->task_queues()->is_empty(), "Unexpected old generation marking tasks");
|
||||
assert(_heap->global_generation()->task_queues()->is_empty(), "Unexpected global generation marking tasks");
|
||||
} else {
|
||||
assert(request.generation->is_young(), "Expected degenerated young cycle, if not global.");
|
||||
ShenandoahOldGeneration* old = _heap->old_generation();
|
||||
if (old->is_bootstrapping()) {
|
||||
old->transition_to(ShenandoahOldGeneration::MARKING);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -681,7 +672,7 @@ bool ShenandoahGenerationalControlThread::request_concurrent_gc(ShenandoahGenera
|
||||
// Cancel the old GC and wait for the control thread to start servicing the new request.
|
||||
log_info(gc)("Preempting old generation mark to allow %s GC", generation->name());
|
||||
while (gc_mode() == servicing_old) {
|
||||
ShenandoahHeap::heap()->cancel_gc(GCCause::_shenandoah_concurrent_gc);
|
||||
_heap->cancel_gc(GCCause::_shenandoah_concurrent_gc);
|
||||
notify_control_thread(ml, GCCause::_shenandoah_concurrent_gc, generation);
|
||||
ml.wait();
|
||||
}
|
||||
|
||||
@ -114,7 +114,7 @@ ShenandoahOldGeneration::ShenandoahOldGeneration(uint max_queues)
|
||||
_promotable_regular_regions(0),
|
||||
_is_parsable(true),
|
||||
_card_scan(nullptr),
|
||||
_state(WAITING_FOR_BOOTSTRAP),
|
||||
_state(IDLE),
|
||||
_growth_percent_before_collection(INITIAL_GROWTH_PERCENT_BEFORE_COLLECTION)
|
||||
{
|
||||
assert(type() == ShenandoahGenerationType::OLD, "OO sanity");
|
||||
@ -339,7 +339,7 @@ void ShenandoahOldGeneration::cancel_gc() {
|
||||
shenandoah_assert_safepoint();
|
||||
if (is_idle()) {
|
||||
#ifdef ASSERT
|
||||
validate_waiting_for_bootstrap();
|
||||
validate_idle();
|
||||
#endif
|
||||
} else {
|
||||
log_info(gc)("Terminating old gc cycle.");
|
||||
@ -350,7 +350,7 @@ void ShenandoahOldGeneration::cancel_gc() {
|
||||
// Remove old generation access to young generation mark queues
|
||||
ShenandoahHeap::heap()->young_generation()->set_old_gen_task_queues(nullptr);
|
||||
// Transition to IDLE now.
|
||||
transition_to(ShenandoahOldGeneration::WAITING_FOR_BOOTSTRAP);
|
||||
transition_to(ShenandoahOldGeneration::IDLE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -477,9 +477,8 @@ void ShenandoahOldGeneration::prepare_regions_and_collection_set(bool concurrent
|
||||
|
||||
const char* ShenandoahOldGeneration::state_name(State state) {
|
||||
switch (state) {
|
||||
case WAITING_FOR_BOOTSTRAP: return "Waiting for Bootstrap";
|
||||
case IDLE: return "Idle";
|
||||
case FILLING: return "Coalescing";
|
||||
case BOOTSTRAPPING: return "Bootstrapping";
|
||||
case MARKING: return "Marking";
|
||||
case EVACUATING: return "Evacuating";
|
||||
case EVACUATING_AFTER_GLOBAL: return "Evacuating (G)";
|
||||
@ -517,7 +516,7 @@ void ShenandoahOldGeneration::transition_to(State new_state) {
|
||||
// the old generation in the respective states (EVACUATING or FILLING). After a Full GC,
|
||||
// the mark bitmaps are all reset, all regions are parsable and the mark context will
|
||||
// not be "complete". After a Full GC, remembered set scans will _not_ use the mark bitmap
|
||||
// and we expect the old generation to be waiting for bootstrap.
|
||||
// and we expect the old generation to be idle.
|
||||
//
|
||||
// +-----------------+
|
||||
// +------------> | FILLING | <---+
|
||||
@ -526,19 +525,12 @@ void ShenandoahOldGeneration::transition_to(State new_state) {
|
||||
// | | | |
|
||||
// | | | Filling Complete | <-> A global collection may
|
||||
// | | v | move the old generation
|
||||
// | | +-----------------+ | directly from waiting for
|
||||
// +-- |-- |--------> | WAITING | | bootstrap to filling or
|
||||
// | | | +---- | FOR BOOTSTRAP | ----+ evacuating. It may also
|
||||
// | | | | +-----------------+ move from filling to waiting
|
||||
// | | | | | for bootstrap.
|
||||
// | | | | | Reset Bitmap
|
||||
// | | | | v
|
||||
// | | | | +-----------------+ +----------------------+
|
||||
// | | | | | BOOTSTRAP | <-> | YOUNG GC |
|
||||
// | | | | | | | (RSet Parses Region) |
|
||||
// | | | | +-----------------+ +----------------------+
|
||||
// | | +-----------------+ | directly from idle to
|
||||
// +-- |-- |--------> | IDLE | | filling or evacuating.
|
||||
// | | | +---- | | ----+ It may also move from
|
||||
// | | | | +-----------------+ filling to idle.
|
||||
// | | | | |
|
||||
// | | | | | Old Marking
|
||||
// | | | | | Reset Bitmap + Start Marking
|
||||
// | | | | v
|
||||
// | | | | +-----------------+ +----------------------+
|
||||
// | | | | | MARKING | <-> | YOUNG GC |
|
||||
@ -564,29 +556,23 @@ void ShenandoahOldGeneration::validate_transition(State new_state) {
|
||||
ShenandoahGenerationalHeap* heap = ShenandoahGenerationalHeap::heap();
|
||||
switch (new_state) {
|
||||
case FILLING:
|
||||
assert(_state != BOOTSTRAPPING, "Cannot begin making old regions parsable after bootstrapping");
|
||||
assert(is_mark_complete(), "Cannot begin filling without first completing marking, state is '%s'", state_name(_state));
|
||||
assert(_old_heuristics->has_coalesce_and_fill_candidates(), "Cannot begin filling without something to fill.");
|
||||
break;
|
||||
case WAITING_FOR_BOOTSTRAP:
|
||||
case IDLE:
|
||||
// GC cancellation can send us back here from any state.
|
||||
validate_waiting_for_bootstrap();
|
||||
break;
|
||||
case BOOTSTRAPPING:
|
||||
assert(_state == WAITING_FOR_BOOTSTRAP, "Cannot reset bitmap without making old regions parsable, state is '%s'", state_name(_state));
|
||||
assert(_old_heuristics->unprocessed_old_collection_candidates() == 0, "Cannot bootstrap with mixed collection candidates");
|
||||
assert(!heap->is_prepare_for_old_mark_in_progress(), "Cannot still be making old regions parsable.");
|
||||
validate_idle();
|
||||
break;
|
||||
case MARKING:
|
||||
assert(_state == BOOTSTRAPPING, "Must have finished bootstrapping before marking, state is '%s'", state_name(_state));
|
||||
assert(heap->young_generation()->old_gen_task_queues() != nullptr, "Young generation needs old mark queues.");
|
||||
assert(heap->is_concurrent_old_mark_in_progress(), "Should be marking old now.");
|
||||
assert(_state == IDLE, "Must be idle before marking, state is '%s'", state_name(_state));
|
||||
assert(_old_heuristics->unprocessed_old_collection_candidates() == 0, "Cannot start marking with mixed collection candidates");
|
||||
assert(!heap->is_prepare_for_old_mark_in_progress(), "Cannot still be making old regions parsable.");
|
||||
break;
|
||||
case EVACUATING_AFTER_GLOBAL:
|
||||
assert(_state == EVACUATING, "Must have been evacuating, state is '%s'", state_name(_state));
|
||||
break;
|
||||
case EVACUATING:
|
||||
assert(_state == WAITING_FOR_BOOTSTRAP || _state == MARKING, "Cannot have old collection candidates without first marking, state is '%s'", state_name(_state));
|
||||
assert(_state == IDLE || _state == MARKING, "Cannot have old collection candidates without first marking, state is '%s'", state_name(_state));
|
||||
assert(_old_heuristics->unprocessed_old_collection_candidates() > 0, "Must have collection candidates here.");
|
||||
break;
|
||||
default:
|
||||
@ -594,10 +580,10 @@ void ShenandoahOldGeneration::validate_transition(State new_state) {
|
||||
}
|
||||
}
|
||||
|
||||
bool ShenandoahOldGeneration::validate_waiting_for_bootstrap() {
|
||||
bool ShenandoahOldGeneration::validate_idle() {
|
||||
ShenandoahHeap* heap = ShenandoahHeap::heap();
|
||||
assert(!heap->is_concurrent_old_mark_in_progress(), "Cannot become ready for bootstrap during old mark.");
|
||||
assert(heap->young_generation()->old_gen_task_queues() == nullptr, "Cannot become ready for bootstrap when still setup for bootstrapping.");
|
||||
assert(!heap->is_concurrent_old_mark_in_progress(), "Cannot be idle during old mark.");
|
||||
assert(heap->young_generation()->old_gen_task_queues() == nullptr, "Cannot be idle when still setup for bootstrapping.");
|
||||
assert(!is_concurrent_mark_in_progress(), "Cannot be marking in IDLE");
|
||||
assert(!heap->young_generation()->is_bootstrap_cycle(), "Cannot have old mark queues if IDLE");
|
||||
assert(!_old_heuristics->has_coalesce_and_fill_candidates(), "Cannot have coalesce and fill candidates in IDLE");
|
||||
@ -733,7 +719,7 @@ void ShenandoahOldGeneration::set_parsable(bool parsable) {
|
||||
// that we would unload classes and make everything parsable. But, we know
|
||||
// that now so we can override this state.
|
||||
abandon_collection_candidates();
|
||||
transition_to(ShenandoahOldGeneration::WAITING_FOR_BOOTSTRAP);
|
||||
transition_to(ShenandoahOldGeneration::IDLE);
|
||||
break;
|
||||
default:
|
||||
// We can get here during a full GC. The full GC will cancel anything
|
||||
@ -750,7 +736,7 @@ void ShenandoahOldGeneration::complete_mixed_evacuations() {
|
||||
assert(is_doing_mixed_evacuations(), "Mixed evacuations should be in progress");
|
||||
if (!_old_heuristics->has_coalesce_and_fill_candidates()) {
|
||||
// No candidate regions to coalesce and fill
|
||||
transition_to(ShenandoahOldGeneration::WAITING_FOR_BOOTSTRAP);
|
||||
transition_to(ShenandoahOldGeneration::IDLE);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -764,7 +750,7 @@ void ShenandoahOldGeneration::complete_mixed_evacuations() {
|
||||
// more to do.
|
||||
assert(state() == ShenandoahOldGeneration::EVACUATING_AFTER_GLOBAL, "Should be evacuating after a global cycle");
|
||||
abandon_collection_candidates();
|
||||
transition_to(ShenandoahOldGeneration::WAITING_FOR_BOOTSTRAP);
|
||||
transition_to(ShenandoahOldGeneration::IDLE);
|
||||
}
|
||||
|
||||
void ShenandoahOldGeneration::abandon_mixed_evacuations() {
|
||||
@ -774,7 +760,7 @@ void ShenandoahOldGeneration::abandon_mixed_evacuations() {
|
||||
break;
|
||||
case ShenandoahOldGeneration::EVACUATING_AFTER_GLOBAL:
|
||||
abandon_collection_candidates();
|
||||
transition_to(ShenandoahOldGeneration::WAITING_FOR_BOOTSTRAP);
|
||||
transition_to(ShenandoahOldGeneration::IDLE);
|
||||
break;
|
||||
default:
|
||||
log_warning(gc)("Abandon mixed evacuations in unexpected state: %s", state_name(state()));
|
||||
|
||||
@ -256,11 +256,7 @@ public:
|
||||
}
|
||||
|
||||
bool is_idle() const {
|
||||
return state() == WAITING_FOR_BOOTSTRAP;
|
||||
}
|
||||
|
||||
bool is_bootstrapping() const {
|
||||
return state() == BOOTSTRAPPING;
|
||||
return state() == IDLE;
|
||||
}
|
||||
|
||||
// Amount of live memory (bytes) in regions waiting for mixed collections
|
||||
@ -271,11 +267,11 @@ public:
|
||||
|
||||
public:
|
||||
enum State {
|
||||
FILLING, WAITING_FOR_BOOTSTRAP, BOOTSTRAPPING, MARKING, EVACUATING, EVACUATING_AFTER_GLOBAL
|
||||
FILLING, IDLE, MARKING, EVACUATING, EVACUATING_AFTER_GLOBAL
|
||||
};
|
||||
|
||||
#ifdef ASSERT
|
||||
bool validate_waiting_for_bootstrap();
|
||||
bool validate_idle();
|
||||
#endif
|
||||
|
||||
private:
|
||||
@ -318,7 +314,7 @@ public:
|
||||
size_t usage_trigger_threshold() const;
|
||||
|
||||
bool can_start_gc() {
|
||||
return _state == WAITING_FOR_BOOTSTRAP;
|
||||
return _state == IDLE;
|
||||
}
|
||||
|
||||
static const char* state_name(State state);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user