8222186: Shenandoah should not uncommit below minimum heap size
Reviewed-by: zgu, rkennke
This commit is contained in:
parent
6453df40be
commit
321615029c
@ -139,6 +139,11 @@ void ShenandoahArguments::initialize() {
|
||||
FLAG_SET_DEFAULT(ShenandoahUncommit, false);
|
||||
}
|
||||
|
||||
if ((InitialHeapSize == MaxHeapSize) && ShenandoahUncommit) {
|
||||
log_info(gc)("Min heap equals to max heap, disabling ShenandoahUncommit");
|
||||
FLAG_SET_DEFAULT(ShenandoahUncommit, false);
|
||||
}
|
||||
|
||||
// If class unloading is disabled, no unloading for concurrent cycles as well.
|
||||
// If class unloading is enabled, users should opt-in for unloading during
|
||||
// concurrent cycles.
|
||||
|
@ -462,9 +462,11 @@ void ShenandoahControlThread::service_stw_degenerated_cycle(GCCause::Cause cause
|
||||
void ShenandoahControlThread::service_uncommit(double shrink_before) {
|
||||
ShenandoahHeap* heap = ShenandoahHeap::heap();
|
||||
|
||||
// Scan through the heap and 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.
|
||||
// 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;
|
||||
|
||||
bool has_work = false;
|
||||
for (size_t i = 0; i < heap->num_regions(); i++) {
|
||||
|
@ -141,6 +141,7 @@ jint ShenandoahHeap::initialize() {
|
||||
//
|
||||
|
||||
size_t init_byte_size = collector_policy()->initial_heap_byte_size();
|
||||
size_t min_byte_size = collector_policy()->min_heap_byte_size();
|
||||
size_t max_byte_size = collector_policy()->max_heap_byte_size();
|
||||
size_t heap_alignment = collector_policy()->heap_alignment();
|
||||
|
||||
@ -159,8 +160,13 @@ jint ShenandoahHeap::initialize() {
|
||||
size_t num_committed_regions = init_byte_size / reg_size_bytes;
|
||||
num_committed_regions = MIN2(num_committed_regions, _num_regions);
|
||||
assert(num_committed_regions <= _num_regions, "sanity");
|
||||
|
||||
_initial_size = num_committed_regions * reg_size_bytes;
|
||||
|
||||
size_t num_min_regions = min_byte_size / reg_size_bytes;
|
||||
num_min_regions = MIN2(num_min_regions, _num_regions);
|
||||
assert(num_min_regions <= _num_regions, "sanity");
|
||||
_minimum_size = num_min_regions * reg_size_bytes;
|
||||
|
||||
_committed = _initial_size;
|
||||
|
||||
size_t heap_page_size = UseLargePages ? (size_t)os::large_page_size() : (size_t)os::vm_page_size();
|
||||
@ -351,8 +357,11 @@ jint ShenandoahHeap::initialize() {
|
||||
|
||||
_control_thread = new ShenandoahControlThread();
|
||||
|
||||
log_info(gc, init)("Initialize Shenandoah heap with initial size " SIZE_FORMAT "%s",
|
||||
byte_size_in_proper_unit(_initial_size), proper_unit_for_byte_size(_initial_size));
|
||||
log_info(gc, init)("Initialize Shenandoah heap: " SIZE_FORMAT "%s initial, " SIZE_FORMAT "%s min, " SIZE_FORMAT "%s max",
|
||||
byte_size_in_proper_unit(_initial_size), proper_unit_for_byte_size(_initial_size),
|
||||
byte_size_in_proper_unit(_minimum_size), proper_unit_for_byte_size(_minimum_size),
|
||||
byte_size_in_proper_unit(max_capacity()), proper_unit_for_byte_size(max_capacity())
|
||||
);
|
||||
|
||||
log_info(gc, init)("Safepointing mechanism: %s",
|
||||
SafepointMechanism::uses_thread_local_poll() ? "thread-local poll" :
|
||||
@ -622,6 +631,10 @@ size_t ShenandoahHeap::max_capacity() const {
|
||||
return _num_regions * ShenandoahHeapRegion::region_size_bytes();
|
||||
}
|
||||
|
||||
size_t ShenandoahHeap::min_capacity() const {
|
||||
return _minimum_size;
|
||||
}
|
||||
|
||||
size_t ShenandoahHeap::initial_capacity() const {
|
||||
return _initial_size;
|
||||
}
|
||||
@ -635,12 +648,22 @@ bool ShenandoahHeap::is_in(const void* p) const {
|
||||
void ShenandoahHeap::op_uncommit(double shrink_before) {
|
||||
assert (ShenandoahUncommit, "should be enabled");
|
||||
|
||||
// Application allocates from the beginning of the heap, and GC allocates at
|
||||
// the end of it. It is more efficient to uncommit from the end, so that applications
|
||||
// could enjoy the near committed regions. GC allocations are much less frequent,
|
||||
// and therefore can accept the committing costs.
|
||||
|
||||
size_t count = 0;
|
||||
for (size_t i = 0; i < num_regions(); i++) {
|
||||
ShenandoahHeapRegion* r = get_region(i);
|
||||
for (size_t i = num_regions(); i > 0; i--) { // care about size_t underflow
|
||||
ShenandoahHeapRegion* r = get_region(i - 1);
|
||||
if (r->is_empty_committed() && (r->empty_time() < shrink_before)) {
|
||||
ShenandoahHeapLocker locker(lock());
|
||||
if (r->is_empty_committed()) {
|
||||
// Do not uncommit below minimal capacity
|
||||
if (committed() < min_capacity() + ShenandoahHeapRegion::region_size_bytes()) {
|
||||
break;
|
||||
}
|
||||
|
||||
r->make_uncommitted();
|
||||
count++;
|
||||
}
|
||||
|
@ -198,6 +198,7 @@ public:
|
||||
//
|
||||
private:
|
||||
size_t _initial_size;
|
||||
size_t _minimum_size;
|
||||
DEFINE_PAD_MINUS_SIZE(0, DEFAULT_CACHE_LINE_SIZE, sizeof(volatile size_t));
|
||||
volatile size_t _used;
|
||||
volatile size_t _committed;
|
||||
@ -216,6 +217,7 @@ public:
|
||||
size_t bytes_allocated_since_gc_start();
|
||||
void reset_bytes_allocated_since_gc_start();
|
||||
|
||||
size_t min_capacity() const;
|
||||
size_t max_capacity() const;
|
||||
size_t initial_capacity() const;
|
||||
size_t capacity() const;
|
||||
|
@ -31,6 +31,8 @@
|
||||
* @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xmx1g TestMemoryMXBeans -1 1024
|
||||
* @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xms1g -Xmx1g TestMemoryMXBeans 1024 1024
|
||||
* @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xms128m -Xmx1g TestMemoryMXBeans 128 1024
|
||||
* @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xms1g -Xmx1g -XX:ShenandoahUncommitDelay=0 TestMemoryMXBeans 1024 1024
|
||||
* @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xms128m -Xmx1g -XX:ShenandoahUncommitDelay=0 TestMemoryMXBeans 128 1024
|
||||
*/
|
||||
|
||||
import java.lang.management.*;
|
||||
@ -46,6 +48,9 @@ public class TestMemoryMXBeans {
|
||||
long initSize = 1L * Integer.parseInt(args[0]) * 1024 * 1024;
|
||||
long maxSize = 1L * Integer.parseInt(args[1]) * 1024 * 1024;
|
||||
|
||||
// wait for GC to uncommit
|
||||
Thread.sleep(1000);
|
||||
|
||||
testMemoryBean(initSize, maxSize);
|
||||
}
|
||||
|
||||
@ -65,7 +70,15 @@ public class TestMemoryMXBeans {
|
||||
throw new IllegalStateException("Max heap size is wrong: " + heapMax + " vs " + maxSize);
|
||||
}
|
||||
if (initSize > 0 && maxSize > 0 && initSize != maxSize && heapCommitted == heapMax) {
|
||||
throw new IllegalStateException("Init committed heap size is wrong: " + heapCommitted +
|
||||
throw new IllegalStateException("Committed heap size is max: " + heapCommitted +
|
||||
" (init: " + initSize + ", max: " + maxSize + ")");
|
||||
}
|
||||
if (initSize > 0 && maxSize > 0 && initSize == maxSize && heapCommitted != heapMax) {
|
||||
throw new IllegalStateException("Committed heap size is not max: " + heapCommitted +
|
||||
" (init: " + initSize + ", max: " + maxSize + ")");
|
||||
}
|
||||
if (initSize > 0 && heapCommitted < initSize) {
|
||||
throw new IllegalStateException("Committed heap size is below min: " + heapCommitted +
|
||||
" (init: " + initSize + ", max: " + maxSize + ")");
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user