8252660: Shenandoah: support manageable SoftMaxHeapSize option

Reviewed-by: zgu
This commit is contained in:
Aleksey Shipilev 2020-09-02 18:37:31 +02:00
parent 261eb76ea2
commit c61204b3f3
11 changed files with 314 additions and 33 deletions

View file

@ -103,6 +103,9 @@ void ShenandoahControlThread::run_service() {
// This control loop iteration have seen this much allocations.
size_t allocs_seen = Atomic::xchg(&_allocs_seen, (size_t)0);
// Check if we have seen a new target for soft max heap size.
bool soft_max_changed = check_soft_max_changed();
// Choose which GC mode to run in. The block below should select a single mode.
GCMode mode = none;
GCCause::Cause cause = GCCause::_last_gc_cause;
@ -291,13 +294,20 @@ void ShenandoahControlThread::run_service() {
double current = os::elapsedTime();
if (ShenandoahUncommit && (explicit_gc_requested || (current - last_shrink_time > shrink_period))) {
// Try to uncommit enough stale regions. Explicit GC tries to uncommit everything.
// Regular paths uncommit only occasionally.
double shrink_before = explicit_gc_requested ?
if (ShenandoahUncommit && (explicit_gc_requested || soft_max_changed || (current - last_shrink_time > shrink_period))) {
// Explicit GC tries to uncommit everything down to min capacity.
// Soft max change tries to uncommit everything down to target capacity.
// Periodic uncommit tries to uncommit suitable regions down to min capacity.
double shrink_before = (explicit_gc_requested || soft_max_changed) ?
current :
current - (ShenandoahUncommitDelay / 1000.0);
service_uncommit(shrink_before);
size_t shrink_until = soft_max_changed ?
heap->soft_max_capacity() :
heap->min_capacity();
service_uncommit(shrink_before, shrink_until);
heap->phase_timings()->flush_cycle_to_global();
last_shrink_time = current;
}
@ -320,6 +330,25 @@ void ShenandoahControlThread::run_service() {
}
}
bool ShenandoahControlThread::check_soft_max_changed() const {
ShenandoahHeap* heap = ShenandoahHeap::heap();
size_t new_soft_max = Atomic::load(&SoftMaxHeapSize);
size_t old_soft_max = heap->soft_max_capacity();
if (new_soft_max != old_soft_max) {
new_soft_max = MAX2(heap->min_capacity(), new_soft_max);
new_soft_max = MIN2(heap->max_capacity(), new_soft_max);
if (new_soft_max != old_soft_max) {
log_info(gc)("Soft Max Heap Size: " SIZE_FORMAT "%s -> " SIZE_FORMAT "%s",
byte_size_in_proper_unit(old_soft_max), proper_unit_for_byte_size(old_soft_max),
byte_size_in_proper_unit(new_soft_max), proper_unit_for_byte_size(new_soft_max)
);
heap->set_soft_max_capacity(new_soft_max);
return true;
}
}
return false;
}
void ShenandoahControlThread::service_concurrent_normal_cycle(GCCause::Cause cause) {
// Normal cycle goes via all concurrent phases. If allocation failure (af) happens during
// any of the concurrent phases, it first degrades to Degenerated GC and completes GC there.
@ -479,14 +508,14 @@ void ShenandoahControlThread::service_stw_degenerated_cycle(GCCause::Cause cause
heap->shenandoah_policy()->record_success_degenerated();
}
void ShenandoahControlThread::service_uncommit(double shrink_before) {
void ShenandoahControlThread::service_uncommit(double shrink_before, size_t shrink_until) {
ShenandoahHeap* heap = ShenandoahHeap::heap();
// Determine if there is work to do. This avoids taking heap lock if there is
// no work available, avoids spamming logs with superfluous logging messages,
// and minimises the amount of work while locks are taken.
if (heap->committed() <= heap->min_capacity()) return;
if (heap->committed() <= shrink_until) return;
bool has_work = false;
for (size_t i = 0; i < heap->num_regions(); i++) {
@ -498,7 +527,7 @@ void ShenandoahControlThread::service_uncommit(double shrink_before) {
}
if (has_work) {
heap->entry_uncommit(shrink_before);
heap->entry_uncommit(shrink_before, shrink_until);
}
}