mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-20 11:04:34 +02:00
8252660: Shenandoah: support manageable SoftMaxHeapSize option
Reviewed-by: zgu
This commit is contained in:
parent
261eb76ea2
commit
c61204b3f3
11 changed files with 314 additions and 33 deletions
|
@ -60,7 +60,7 @@ void ShenandoahAdaptiveHeuristics::choose_collection_set_from_regiondata(Shenand
|
||||||
// we hit max_cset. When max_cset is hit, we terminate the cset selection. Note that in this scheme,
|
// we hit max_cset. When max_cset is hit, we terminate the cset selection. Note that in this scheme,
|
||||||
// ShenandoahGarbageThreshold is the soft threshold which would be ignored until min_garbage is hit.
|
// ShenandoahGarbageThreshold is the soft threshold which would be ignored until min_garbage is hit.
|
||||||
|
|
||||||
size_t capacity = ShenandoahHeap::heap()->max_capacity();
|
size_t capacity = ShenandoahHeap::heap()->soft_max_capacity();
|
||||||
size_t max_cset = (size_t)((1.0 * capacity / 100 * ShenandoahEvacReserve) / ShenandoahEvacWaste);
|
size_t max_cset = (size_t)((1.0 * capacity / 100 * ShenandoahEvacReserve) / ShenandoahEvacWaste);
|
||||||
size_t free_target = (capacity / 100 * ShenandoahMinFreeThreshold) + max_cset;
|
size_t free_target = (capacity / 100 * ShenandoahMinFreeThreshold) + max_cset;
|
||||||
size_t min_garbage = (free_target > actual_free ? (free_target - actual_free) : 0);
|
size_t min_garbage = (free_target > actual_free ? (free_target - actual_free) : 0);
|
||||||
|
@ -102,9 +102,14 @@ void ShenandoahAdaptiveHeuristics::record_cycle_start() {
|
||||||
|
|
||||||
bool ShenandoahAdaptiveHeuristics::should_start_gc() const {
|
bool ShenandoahAdaptiveHeuristics::should_start_gc() const {
|
||||||
ShenandoahHeap* heap = ShenandoahHeap::heap();
|
ShenandoahHeap* heap = ShenandoahHeap::heap();
|
||||||
size_t capacity = heap->max_capacity();
|
size_t max_capacity = heap->max_capacity();
|
||||||
|
size_t capacity = heap->soft_max_capacity();
|
||||||
size_t available = heap->free_set()->available();
|
size_t available = heap->free_set()->available();
|
||||||
|
|
||||||
|
// Make sure the code below treats available without the soft tail.
|
||||||
|
size_t soft_tail = max_capacity - capacity;
|
||||||
|
available = (available > soft_tail) ? (available - soft_tail) : 0;
|
||||||
|
|
||||||
// Check if we are falling below the worst limit, time to trigger the GC, regardless of
|
// Check if we are falling below the worst limit, time to trigger the GC, regardless of
|
||||||
// anything else.
|
// anything else.
|
||||||
size_t min_threshold = capacity / 100 * ShenandoahMinFreeThreshold;
|
size_t min_threshold = capacity / 100 * ShenandoahMinFreeThreshold;
|
||||||
|
|
|
@ -47,9 +47,14 @@ ShenandoahCompactHeuristics::ShenandoahCompactHeuristics() : ShenandoahHeuristic
|
||||||
bool ShenandoahCompactHeuristics::should_start_gc() const {
|
bool ShenandoahCompactHeuristics::should_start_gc() const {
|
||||||
ShenandoahHeap* heap = ShenandoahHeap::heap();
|
ShenandoahHeap* heap = ShenandoahHeap::heap();
|
||||||
|
|
||||||
size_t capacity = heap->max_capacity();
|
size_t max_capacity = heap->max_capacity();
|
||||||
|
size_t capacity = heap->soft_max_capacity();
|
||||||
size_t available = heap->free_set()->available();
|
size_t available = heap->free_set()->available();
|
||||||
|
|
||||||
|
// Make sure the code below treats available without the soft tail.
|
||||||
|
size_t soft_tail = max_capacity - capacity;
|
||||||
|
available = (available > soft_tail) ? (available - soft_tail) : 0;
|
||||||
|
|
||||||
size_t threshold_bytes_allocated = capacity / 100 * ShenandoahAllocationThreshold;
|
size_t threshold_bytes_allocated = capacity / 100 * ShenandoahAllocationThreshold;
|
||||||
size_t min_threshold = capacity / 100 * ShenandoahMinFreeThreshold;
|
size_t min_threshold = capacity / 100 * ShenandoahMinFreeThreshold;
|
||||||
|
|
||||||
|
|
|
@ -58,8 +58,8 @@ void ShenandoahPassiveHeuristics::choose_collection_set_from_regiondata(Shenando
|
||||||
|
|
||||||
// Do not select too large CSet that would overflow the available free space.
|
// Do not select too large CSet that would overflow the available free space.
|
||||||
// Take at least the entire evacuation reserve, and be free to overflow to free space.
|
// Take at least the entire evacuation reserve, and be free to overflow to free space.
|
||||||
size_t capacity = ShenandoahHeap::heap()->max_capacity();
|
size_t max_capacity = ShenandoahHeap::heap()->max_capacity();
|
||||||
size_t available = MAX2(capacity / 100 * ShenandoahEvacReserve, actual_free);
|
size_t available = MAX2(max_capacity / 100 * ShenandoahEvacReserve, actual_free);
|
||||||
size_t max_cset = (size_t)(available / ShenandoahEvacWaste);
|
size_t max_cset = (size_t)(available / ShenandoahEvacWaste);
|
||||||
|
|
||||||
log_info(gc, ergo)("CSet Selection. Actual Free: " SIZE_FORMAT "%s, Max CSet: " SIZE_FORMAT "%s",
|
log_info(gc, ergo)("CSet Selection. Actual Free: " SIZE_FORMAT "%s, Max CSet: " SIZE_FORMAT "%s",
|
||||||
|
|
|
@ -42,8 +42,14 @@ ShenandoahStaticHeuristics::~ShenandoahStaticHeuristics() {}
|
||||||
bool ShenandoahStaticHeuristics::should_start_gc() const {
|
bool ShenandoahStaticHeuristics::should_start_gc() const {
|
||||||
ShenandoahHeap* heap = ShenandoahHeap::heap();
|
ShenandoahHeap* heap = ShenandoahHeap::heap();
|
||||||
|
|
||||||
size_t capacity = heap->max_capacity();
|
size_t max_capacity = heap->max_capacity();
|
||||||
|
size_t capacity = heap->soft_max_capacity();
|
||||||
size_t available = heap->free_set()->available();
|
size_t available = heap->free_set()->available();
|
||||||
|
|
||||||
|
// Make sure the code below treats available without the soft tail.
|
||||||
|
size_t soft_tail = max_capacity - capacity;
|
||||||
|
available = (available > soft_tail) ? (available - soft_tail) : 0;
|
||||||
|
|
||||||
size_t threshold_available = capacity / 100 * ShenandoahMinFreeThreshold;
|
size_t threshold_available = capacity / 100 * ShenandoahMinFreeThreshold;
|
||||||
|
|
||||||
if (available < threshold_available) {
|
if (available < threshold_available) {
|
||||||
|
|
|
@ -103,6 +103,9 @@ void ShenandoahControlThread::run_service() {
|
||||||
// This control loop iteration have seen this much allocations.
|
// This control loop iteration have seen this much allocations.
|
||||||
size_t allocs_seen = Atomic::xchg(&_allocs_seen, (size_t)0);
|
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.
|
// Choose which GC mode to run in. The block below should select a single mode.
|
||||||
GCMode mode = none;
|
GCMode mode = none;
|
||||||
GCCause::Cause cause = GCCause::_last_gc_cause;
|
GCCause::Cause cause = GCCause::_last_gc_cause;
|
||||||
|
@ -291,13 +294,20 @@ void ShenandoahControlThread::run_service() {
|
||||||
|
|
||||||
double current = os::elapsedTime();
|
double current = os::elapsedTime();
|
||||||
|
|
||||||
if (ShenandoahUncommit && (explicit_gc_requested || (current - last_shrink_time > shrink_period))) {
|
if (ShenandoahUncommit && (explicit_gc_requested || soft_max_changed || (current - last_shrink_time > shrink_period))) {
|
||||||
// Try to uncommit enough stale regions. Explicit GC tries to uncommit everything.
|
// Explicit GC tries to uncommit everything down to min capacity.
|
||||||
// Regular paths uncommit only occasionally.
|
// Soft max change tries to uncommit everything down to target capacity.
|
||||||
double shrink_before = explicit_gc_requested ?
|
// Periodic uncommit tries to uncommit suitable regions down to min capacity.
|
||||||
|
|
||||||
|
double shrink_before = (explicit_gc_requested || soft_max_changed) ?
|
||||||
current :
|
current :
|
||||||
current - (ShenandoahUncommitDelay / 1000.0);
|
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();
|
heap->phase_timings()->flush_cycle_to_global();
|
||||||
last_shrink_time = current;
|
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) {
|
void ShenandoahControlThread::service_concurrent_normal_cycle(GCCause::Cause cause) {
|
||||||
// Normal cycle goes via all concurrent phases. If allocation failure (af) happens during
|
// 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.
|
// 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();
|
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();
|
ShenandoahHeap* heap = ShenandoahHeap::heap();
|
||||||
|
|
||||||
// Determine if there is work to do. This avoids taking heap lock if there is
|
// 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,
|
// no work available, avoids spamming logs with superfluous logging messages,
|
||||||
// and minimises the amount of work while locks are taken.
|
// 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;
|
bool has_work = false;
|
||||||
for (size_t i = 0; i < heap->num_regions(); i++) {
|
for (size_t i = 0; i < heap->num_regions(); i++) {
|
||||||
|
@ -498,7 +527,7 @@ void ShenandoahControlThread::service_uncommit(double shrink_before) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_work) {
|
if (has_work) {
|
||||||
heap->entry_uncommit(shrink_before);
|
heap->entry_uncommit(shrink_before, shrink_until);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -103,7 +103,7 @@ private:
|
||||||
void service_concurrent_normal_cycle(GCCause::Cause cause);
|
void service_concurrent_normal_cycle(GCCause::Cause cause);
|
||||||
void service_stw_full_cycle(GCCause::Cause cause);
|
void service_stw_full_cycle(GCCause::Cause cause);
|
||||||
void service_stw_degenerated_cycle(GCCause::Cause cause, ShenandoahHeap::ShenandoahDegenPoint point);
|
void service_stw_degenerated_cycle(GCCause::Cause cause, ShenandoahHeap::ShenandoahDegenPoint point);
|
||||||
void service_uncommit(double shrink_before);
|
void service_uncommit(double shrink_before, size_t shrink_until);
|
||||||
|
|
||||||
bool try_set_alloc_failure_gc();
|
bool try_set_alloc_failure_gc();
|
||||||
void notify_alloc_failure_waiters();
|
void notify_alloc_failure_waiters();
|
||||||
|
@ -120,6 +120,9 @@ private:
|
||||||
void handle_requested_gc(GCCause::Cause cause);
|
void handle_requested_gc(GCCause::Cause cause);
|
||||||
|
|
||||||
bool is_explicit_gc(GCCause::Cause cause) const;
|
bool is_explicit_gc(GCCause::Cause cause) const;
|
||||||
|
|
||||||
|
bool check_soft_max_changed() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Constructor
|
// Constructor
|
||||||
ShenandoahControlThread();
|
ShenandoahControlThread();
|
||||||
|
|
|
@ -163,6 +163,9 @@ jint ShenandoahHeap::initialize() {
|
||||||
assert(num_min_regions <= _num_regions, "sanity");
|
assert(num_min_regions <= _num_regions, "sanity");
|
||||||
_minimum_size = num_min_regions * reg_size_bytes;
|
_minimum_size = num_min_regions * reg_size_bytes;
|
||||||
|
|
||||||
|
// Default to max heap size.
|
||||||
|
_soft_max_size = _num_regions * reg_size_bytes;
|
||||||
|
|
||||||
_committed = _initial_size;
|
_committed = _initial_size;
|
||||||
|
|
||||||
size_t heap_page_size = UseLargePages ? (size_t)os::large_page_size() : (size_t)os::vm_page_size();
|
size_t heap_page_size = UseLargePages ? (size_t)os::large_page_size() : (size_t)os::vm_page_size();
|
||||||
|
@ -538,8 +541,9 @@ void ShenandoahHeap::reset_mark_bitmap() {
|
||||||
|
|
||||||
void ShenandoahHeap::print_on(outputStream* st) const {
|
void ShenandoahHeap::print_on(outputStream* st) const {
|
||||||
st->print_cr("Shenandoah Heap");
|
st->print_cr("Shenandoah Heap");
|
||||||
st->print_cr(" " SIZE_FORMAT "%s total, " SIZE_FORMAT "%s committed, " SIZE_FORMAT "%s used",
|
st->print_cr(" " SIZE_FORMAT "%s max, " SIZE_FORMAT "%s soft max, " SIZE_FORMAT "%s committed, " SIZE_FORMAT "%s used",
|
||||||
byte_size_in_proper_unit(max_capacity()), proper_unit_for_byte_size(max_capacity()),
|
byte_size_in_proper_unit(max_capacity()), proper_unit_for_byte_size(max_capacity()),
|
||||||
|
byte_size_in_proper_unit(soft_max_capacity()), proper_unit_for_byte_size(soft_max_capacity()),
|
||||||
byte_size_in_proper_unit(committed()), proper_unit_for_byte_size(committed()),
|
byte_size_in_proper_unit(committed()), proper_unit_for_byte_size(committed()),
|
||||||
byte_size_in_proper_unit(used()), proper_unit_for_byte_size(used()));
|
byte_size_in_proper_unit(used()), proper_unit_for_byte_size(used()));
|
||||||
st->print_cr(" " SIZE_FORMAT " x " SIZE_FORMAT"%s regions",
|
st->print_cr(" " SIZE_FORMAT " x " SIZE_FORMAT"%s regions",
|
||||||
|
@ -676,6 +680,21 @@ size_t ShenandoahHeap::max_capacity() const {
|
||||||
return _num_regions * ShenandoahHeapRegion::region_size_bytes();
|
return _num_regions * ShenandoahHeapRegion::region_size_bytes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t ShenandoahHeap::soft_max_capacity() const {
|
||||||
|
size_t v = Atomic::load(&_soft_max_size);
|
||||||
|
assert(min_capacity() <= v && v <= max_capacity(),
|
||||||
|
"Should be in bounds: " SIZE_FORMAT " <= " SIZE_FORMAT " <= " SIZE_FORMAT,
|
||||||
|
min_capacity(), v, max_capacity());
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShenandoahHeap::set_soft_max_capacity(size_t v) {
|
||||||
|
assert(min_capacity() <= v && v <= max_capacity(),
|
||||||
|
"Should be in bounds: " SIZE_FORMAT " <= " SIZE_FORMAT " <= " SIZE_FORMAT,
|
||||||
|
min_capacity(), v, max_capacity());
|
||||||
|
Atomic::store(&_soft_max_size, v);
|
||||||
|
}
|
||||||
|
|
||||||
size_t ShenandoahHeap::min_capacity() const {
|
size_t ShenandoahHeap::min_capacity() const {
|
||||||
return _minimum_size;
|
return _minimum_size;
|
||||||
}
|
}
|
||||||
|
@ -690,7 +709,7 @@ bool ShenandoahHeap::is_in(const void* p) const {
|
||||||
return p >= heap_base && p < last_region_end;
|
return p >= heap_base && p < last_region_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShenandoahHeap::op_uncommit(double shrink_before) {
|
void ShenandoahHeap::op_uncommit(double shrink_before, size_t shrink_until) {
|
||||||
assert (ShenandoahUncommit, "should be enabled");
|
assert (ShenandoahUncommit, "should be enabled");
|
||||||
|
|
||||||
// Application allocates from the beginning of the heap, and GC allocates at
|
// Application allocates from the beginning of the heap, and GC allocates at
|
||||||
|
@ -704,8 +723,7 @@ void ShenandoahHeap::op_uncommit(double shrink_before) {
|
||||||
if (r->is_empty_committed() && (r->empty_time() < shrink_before)) {
|
if (r->is_empty_committed() && (r->empty_time() < shrink_before)) {
|
||||||
ShenandoahHeapLocker locker(lock());
|
ShenandoahHeapLocker locker(lock());
|
||||||
if (r->is_empty_committed()) {
|
if (r->is_empty_committed()) {
|
||||||
// Do not uncommit below minimal capacity
|
if (committed() < shrink_until + ShenandoahHeapRegion::region_size_bytes()) {
|
||||||
if (committed() < min_capacity() + ShenandoahHeapRegion::region_size_bytes()) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2960,12 +2978,12 @@ void ShenandoahHeap::entry_preclean() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShenandoahHeap::entry_uncommit(double shrink_before) {
|
void ShenandoahHeap::entry_uncommit(double shrink_before, size_t shrink_until) {
|
||||||
static const char *msg = "Concurrent uncommit";
|
static const char *msg = "Concurrent uncommit";
|
||||||
ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_uncommit, true /* log_heap_usage */);
|
ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_uncommit, true /* log_heap_usage */);
|
||||||
EventMark em("%s", msg);
|
EventMark em("%s", msg);
|
||||||
|
|
||||||
op_uncommit(shrink_before);
|
op_uncommit(shrink_before, shrink_until);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShenandoahHeap::try_inject_alloc_failure() {
|
void ShenandoahHeap::try_inject_alloc_failure() {
|
||||||
|
|
|
@ -158,6 +158,7 @@ public:
|
||||||
private:
|
private:
|
||||||
size_t _initial_size;
|
size_t _initial_size;
|
||||||
size_t _minimum_size;
|
size_t _minimum_size;
|
||||||
|
volatile size_t _soft_max_size;
|
||||||
shenandoah_padding(0);
|
shenandoah_padding(0);
|
||||||
volatile size_t _used;
|
volatile size_t _used;
|
||||||
volatile size_t _committed;
|
volatile size_t _committed;
|
||||||
|
@ -178,11 +179,14 @@ public:
|
||||||
|
|
||||||
size_t min_capacity() const;
|
size_t min_capacity() const;
|
||||||
size_t max_capacity() const;
|
size_t max_capacity() const;
|
||||||
|
size_t soft_max_capacity() const;
|
||||||
size_t initial_capacity() const;
|
size_t initial_capacity() const;
|
||||||
size_t capacity() const;
|
size_t capacity() const;
|
||||||
size_t used() const;
|
size_t used() const;
|
||||||
size_t committed() const;
|
size_t committed() const;
|
||||||
|
|
||||||
|
void set_soft_max_capacity(size_t v);
|
||||||
|
|
||||||
// ---------- Workers handling
|
// ---------- Workers handling
|
||||||
//
|
//
|
||||||
private:
|
private:
|
||||||
|
@ -390,7 +394,7 @@ public:
|
||||||
void entry_evac();
|
void entry_evac();
|
||||||
void entry_updaterefs();
|
void entry_updaterefs();
|
||||||
void entry_cleanup_complete();
|
void entry_cleanup_complete();
|
||||||
void entry_uncommit(double shrink_before);
|
void entry_uncommit(double shrink_before, size_t shrink_until);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Actual work for the phases
|
// Actual work for the phases
|
||||||
|
@ -415,7 +419,7 @@ private:
|
||||||
void op_stw_evac();
|
void op_stw_evac();
|
||||||
void op_updaterefs();
|
void op_updaterefs();
|
||||||
void op_cleanup_complete();
|
void op_cleanup_complete();
|
||||||
void op_uncommit(double shrink_before);
|
void op_uncommit(double shrink_before, size_t shrink_until);
|
||||||
|
|
||||||
void rendezvous_threads();
|
void rendezvous_threads();
|
||||||
|
|
||||||
|
|
|
@ -106,26 +106,26 @@
|
||||||
"How much heap should be free before some heuristics trigger the "\
|
"How much heap should be free before some heuristics trigger the "\
|
||||||
"initial (learning) cycles. Affects cycle frequency on startup " \
|
"initial (learning) cycles. Affects cycle frequency on startup " \
|
||||||
"and after drastic state changes, e.g. after degenerated/full " \
|
"and after drastic state changes, e.g. after degenerated/full " \
|
||||||
"GC cycles. In percents of total heap size.") \
|
"GC cycles. In percents of (soft) max heap size.") \
|
||||||
range(0,100) \
|
range(0,100) \
|
||||||
\
|
\
|
||||||
experimental(uintx, ShenandoahMinFreeThreshold, 10, \
|
experimental(uintx, ShenandoahMinFreeThreshold, 10, \
|
||||||
"How much heap should be free before most heuristics trigger the "\
|
"How much heap should be free before most heuristics trigger the "\
|
||||||
"collection, even without other triggers. Provides the safety " \
|
"collection, even without other triggers. Provides the safety " \
|
||||||
"margin for many heuristics. In percents of total heap size.") \
|
"margin for many heuristics. In percents of (soft) max heap size.")\
|
||||||
range(0,100) \
|
range(0,100) \
|
||||||
\
|
\
|
||||||
experimental(uintx, ShenandoahAllocationThreshold, 0, \
|
experimental(uintx, ShenandoahAllocationThreshold, 0, \
|
||||||
"How many new allocations should happen since the last GC cycle " \
|
"How many new allocations should happen since the last GC cycle " \
|
||||||
"before some heuristics trigger the collection. In percents of " \
|
"before some heuristics trigger the collection. In percents of " \
|
||||||
"total heap size. Set to zero to effectively disable.") \
|
"(soft) max heap size. Set to zero to effectively disable.") \
|
||||||
range(0,100) \
|
range(0,100) \
|
||||||
\
|
\
|
||||||
experimental(uintx, ShenandoahAllocSpikeFactor, 5, \
|
experimental(uintx, ShenandoahAllocSpikeFactor, 5, \
|
||||||
"How much of heap should some heuristics reserve for absorbing " \
|
"How much of heap should some heuristics reserve for absorbing " \
|
||||||
"the allocation spikes. Larger value wastes more memory in " \
|
"the allocation spikes. Larger value wastes more memory in " \
|
||||||
"non-emergency cases, but provides more safety in emergency " \
|
"non-emergency cases, but provides more safety in emergency " \
|
||||||
"cases. In percents of total heap size.") \
|
"cases. In percents of (soft) max heap size.") \
|
||||||
range(0,100) \
|
range(0,100) \
|
||||||
\
|
\
|
||||||
experimental(uintx, ShenandoahLearningSteps, 5, \
|
experimental(uintx, ShenandoahLearningSteps, 5, \
|
||||||
|
|
137
test/hotspot/jtreg/gc/shenandoah/TestDynamicSoftMaxHeapSize.java
Normal file
137
test/hotspot/jtreg/gc/shenandoah/TestDynamicSoftMaxHeapSize.java
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020, Red Hat, Inc. 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
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test TestDynamicSoftMaxHeapSize
|
||||||
|
* @requires vm.gc.Shenandoah & !vm.graal.enabled
|
||||||
|
* @library /test/lib
|
||||||
|
*
|
||||||
|
* @run main/othervm -Xms16m -Xmx512m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
|
||||||
|
* -XX:+UseShenandoahGC -XX:ShenandoahGCMode=passive
|
||||||
|
* -XX:+ShenandoahDegeneratedGC
|
||||||
|
* -Dtarget=10000
|
||||||
|
* TestDynamicSoftMaxHeapSize
|
||||||
|
*
|
||||||
|
* @run main/othervm -Xms16m -Xmx512m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
|
||||||
|
* -XX:+UseShenandoahGC -XX:ShenandoahGCMode=passive
|
||||||
|
* -XX:-ShenandoahDegeneratedGC
|
||||||
|
* -Dtarget=10000
|
||||||
|
* TestDynamicSoftMaxHeapSize
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test TestDynamicSoftMaxHeapSize
|
||||||
|
* @requires vm.gc.Shenandoah & !vm.graal.enabled
|
||||||
|
* @library /test/lib
|
||||||
|
*
|
||||||
|
* @run main/othervm -Xms16m -Xmx512m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
|
||||||
|
* -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=aggressive
|
||||||
|
* -Dtarget=1000
|
||||||
|
* TestDynamicSoftMaxHeapSize
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test TestDynamicSoftMaxHeapSize
|
||||||
|
* @requires vm.gc.Shenandoah & !vm.graal.enabled
|
||||||
|
* @library /test/lib
|
||||||
|
*
|
||||||
|
* @run main/othervm -Xms16m -Xmx512m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
|
||||||
|
* -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=adaptive
|
||||||
|
* -Dtarget=10000
|
||||||
|
* TestDynamicSoftMaxHeapSize
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test TestDynamicSoftMaxHeapSize
|
||||||
|
* @requires vm.gc.Shenandoah & !vm.graal.enabled
|
||||||
|
* @library /test/lib
|
||||||
|
*
|
||||||
|
* @run main/othervm -Xms16m -Xmx512m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
|
||||||
|
* -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=static
|
||||||
|
* -Dtarget=10000
|
||||||
|
* TestDynamicSoftMaxHeapSize
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test TestDynamicSoftMaxHeapSize
|
||||||
|
* @requires vm.gc.Shenandoah & !vm.graal.enabled
|
||||||
|
* @library /test/lib
|
||||||
|
*
|
||||||
|
* @run main/othervm -Xms16m -Xmx512m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
|
||||||
|
* -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=compact
|
||||||
|
* -Dtarget=1000
|
||||||
|
* TestDynamicSoftMaxHeapSize
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test TestDynamicSoftMaxHeapSize
|
||||||
|
* @requires vm.gc.Shenandoah & !vm.graal.enabled
|
||||||
|
* @library /test/lib
|
||||||
|
*
|
||||||
|
* @run main/othervm -Xms16m -Xmx512m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
|
||||||
|
* -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGCHeuristics=aggressive
|
||||||
|
* -Dtarget=1000
|
||||||
|
* TestDynamicSoftMaxHeapSize
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test TestDynamicSoftMaxHeapSize
|
||||||
|
* @requires vm.gc.Shenandoah & !vm.graal.enabled
|
||||||
|
* @library /test/lib
|
||||||
|
*
|
||||||
|
* @run main/othervm -Xms16m -Xmx512m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
|
||||||
|
* -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu
|
||||||
|
* -Dtarget=10000
|
||||||
|
* TestDynamicSoftMaxHeapSize
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
import jdk.test.lib.Utils;
|
||||||
|
import jdk.test.lib.process.OutputAnalyzer;
|
||||||
|
import jdk.test.lib.process.ProcessTools;
|
||||||
|
import jdk.test.lib.dcmd.PidJcmdExecutor;
|
||||||
|
|
||||||
|
public class TestDynamicSoftMaxHeapSize {
|
||||||
|
|
||||||
|
static final long TARGET_MB = Long.getLong("target", 10_000); // 10 Gb allocation
|
||||||
|
static final long STRIDE = 10_000_000;
|
||||||
|
|
||||||
|
static volatile Object sink;
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
long count = TARGET_MB * 1024 * 1024 / 16;
|
||||||
|
Random r = Utils.getRandomInstance();
|
||||||
|
PidJcmdExecutor jcmd = new PidJcmdExecutor();
|
||||||
|
|
||||||
|
for (long c = 0; c < count; c += STRIDE) {
|
||||||
|
// Sizes specifically include heaps below Xms and above Xmx to test saturation code.
|
||||||
|
jcmd.execute("VM.set_flag SoftMaxHeapSize " + r.nextInt(768*1024*1024), true);
|
||||||
|
for (long s = 0; s < STRIDE; s++) {
|
||||||
|
sink = new Object();
|
||||||
|
}
|
||||||
|
Thread.sleep(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020, Red Hat, Inc. 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
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test TestSoftMaxHeapSize
|
||||||
|
* @summary Test that Shenandoah checks SoftMaxHeapSize
|
||||||
|
* @requires vm.gc.Shenandoah & !vm.graal.enabled
|
||||||
|
* @library /test/lib
|
||||||
|
* @modules java.base/jdk.internal.misc
|
||||||
|
* java.management
|
||||||
|
* @run driver TestSoftMaxHeapSize
|
||||||
|
*/
|
||||||
|
|
||||||
|
import jdk.test.lib.process.ProcessTools;
|
||||||
|
import jdk.test.lib.process.OutputAnalyzer;
|
||||||
|
|
||||||
|
public class TestSoftMaxHeapSize {
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
{
|
||||||
|
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UnlockExperimentalVMOptions",
|
||||||
|
"-XX:+UseShenandoahGC",
|
||||||
|
"-Xms4m",
|
||||||
|
"-Xmx128m",
|
||||||
|
"-XX:SoftMaxHeapSize=4m",
|
||||||
|
"-version");
|
||||||
|
OutputAnalyzer output = new OutputAnalyzer(pb.start());
|
||||||
|
output.shouldHaveExitValue(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UnlockExperimentalVMOptions",
|
||||||
|
"-XX:+UseShenandoahGC",
|
||||||
|
"-Xms4m",
|
||||||
|
"-Xmx128m",
|
||||||
|
"-XX:SoftMaxHeapSize=128m",
|
||||||
|
"-version");
|
||||||
|
OutputAnalyzer output = new OutputAnalyzer(pb.start());
|
||||||
|
output.shouldHaveExitValue(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UnlockExperimentalVMOptions",
|
||||||
|
"-XX:+UseShenandoahGC",
|
||||||
|
"-Xms4m",
|
||||||
|
"-Xmx128m",
|
||||||
|
"-XX:SoftMaxHeapSize=129m",
|
||||||
|
"-version");
|
||||||
|
OutputAnalyzer output = new OutputAnalyzer(pb.start());
|
||||||
|
output.shouldHaveExitValue(1);
|
||||||
|
output.shouldContain("SoftMaxHeapSize must be less than or equal to the maximum heap size");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue