8248322: G1: Refactor full collection sizing code

Reviewed-by: iwalulya, kbarrett
This commit is contained in:
Thomas Schatzl 2020-07-09 16:22:22 +02:00
parent 65b23ca67a
commit 59e3ebb4a5
4 changed files with 88 additions and 76 deletions

View File

@ -1143,77 +1143,15 @@ void G1CollectedHeap::do_full_collection(bool clear_all_soft_refs) {
void G1CollectedHeap::resize_heap_if_necessary() {
assert_at_safepoint_on_vm_thread();
// Capacity, free and used after the GC counted as full regions to
// include the waste in the following calculations.
const size_t capacity_after_gc = capacity();
const size_t used_after_gc = capacity_after_gc - unused_committed_regions_in_bytes();
bool should_expand;
size_t resize_amount = _heap_sizing_policy->full_collection_resize_amount(should_expand);
// This is enforced in arguments.cpp.
assert(MinHeapFreeRatio <= MaxHeapFreeRatio,
"otherwise the code below doesn't make sense");
// We don't have floating point command-line arguments
const double minimum_free_percentage = (double) MinHeapFreeRatio / 100.0;
const double maximum_used_percentage = 1.0 - minimum_free_percentage;
const double maximum_free_percentage = (double) MaxHeapFreeRatio / 100.0;
const double minimum_used_percentage = 1.0 - maximum_free_percentage;
// We have to be careful here as these two calculations can overflow
// 32-bit size_t's.
double used_after_gc_d = (double) used_after_gc;
double minimum_desired_capacity_d = used_after_gc_d / maximum_used_percentage;
double maximum_desired_capacity_d = used_after_gc_d / minimum_used_percentage;
// Let's make sure that they are both under the max heap size, which
// by default will make them fit into a size_t.
double desired_capacity_upper_bound = (double) MaxHeapSize;
minimum_desired_capacity_d = MIN2(minimum_desired_capacity_d,
desired_capacity_upper_bound);
maximum_desired_capacity_d = MIN2(maximum_desired_capacity_d,
desired_capacity_upper_bound);
// We can now safely turn them into size_t's.
size_t minimum_desired_capacity = (size_t) minimum_desired_capacity_d;
size_t maximum_desired_capacity = (size_t) maximum_desired_capacity_d;
// This assert only makes sense here, before we adjust them
// with respect to the min and max heap size.
assert(minimum_desired_capacity <= maximum_desired_capacity,
"minimum_desired_capacity = " SIZE_FORMAT ", "
"maximum_desired_capacity = " SIZE_FORMAT,
minimum_desired_capacity, maximum_desired_capacity);
// Should not be greater than the heap max size. No need to adjust
// it with respect to the heap min size as it's a lower bound (i.e.,
// we'll try to make the capacity larger than it, not smaller).
minimum_desired_capacity = MIN2(minimum_desired_capacity, MaxHeapSize);
// Should not be less than the heap min size. No need to adjust it
// with respect to the heap max size as it's an upper bound (i.e.,
// we'll try to make the capacity smaller than it, not greater).
maximum_desired_capacity = MAX2(maximum_desired_capacity, MinHeapSize);
if (capacity_after_gc < minimum_desired_capacity) {
// Don't expand unless it's significant
size_t expand_bytes = minimum_desired_capacity - capacity_after_gc;
log_debug(gc, ergo, heap)("Attempt heap expansion (capacity lower than min desired capacity). "
"Capacity: " SIZE_FORMAT "B occupancy: " SIZE_FORMAT "B live: " SIZE_FORMAT "B "
"min_desired_capacity: " SIZE_FORMAT "B (" UINTX_FORMAT " %%)",
capacity_after_gc, used_after_gc, used(), minimum_desired_capacity, MinHeapFreeRatio);
expand(expand_bytes, _workers);
// No expansion, now see if we want to shrink
} else if (capacity_after_gc > maximum_desired_capacity) {
// Capacity too large, compute shrinking size
size_t shrink_bytes = capacity_after_gc - maximum_desired_capacity;
log_debug(gc, ergo, heap)("Attempt heap shrinking (capacity higher than max desired capacity). "
"Capacity: " SIZE_FORMAT "B occupancy: " SIZE_FORMAT "B live: " SIZE_FORMAT "B "
"maximum_desired_capacity: " SIZE_FORMAT "B (" UINTX_FORMAT " %%)",
capacity_after_gc, used_after_gc, used(), maximum_desired_capacity, MaxHeapFreeRatio);
shrink(shrink_bytes);
if (resize_amount == 0) {
return;
} else if (should_expand) {
expand(resize_amount, _workers);
} else {
shrink(resize_amount);
}
}
@ -2939,7 +2877,7 @@ void G1CollectedHeap::verify_after_young_collection(G1HeapVerifier::G1VerifyType
}
void G1CollectedHeap::expand_heap_after_young_collection(){
size_t expand_bytes = _heap_sizing_policy->expansion_amount();
size_t expand_bytes = _heap_sizing_policy->young_collection_expansion_amount();
if (expand_bytes > 0) {
// No need for an ergo logging here,
// expansion_amount() does this when it returns a value > 0.

View File

@ -732,7 +732,7 @@ private:
// Shrink the garbage-first heap by at most the given size (in bytes!).
// (Rounds down to a HeapRegion boundary.)
void shrink(size_t expand_bytes);
void shrink(size_t shrink_bytes);
void shrink_helper(size_t expand_bytes);
#if TASKQUEUE_STATS

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. 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
@ -82,7 +82,7 @@ static void log_expansion(double short_term_pause_time_ratio,
resize_bytes);
}
size_t G1HeapSizingPolicy::expansion_amount() {
size_t G1HeapSizingPolicy::young_collection_expansion_amount() {
assert(GCTimeRatio > 0, "must be");
double long_term_pause_time_ratio = _analytics->long_term_pause_time_ratio();
@ -195,3 +195,74 @@ size_t G1HeapSizingPolicy::expansion_amount() {
return expand_bytes;
}
static size_t target_heap_capacity(size_t used_bytes, uintx free_ratio) {
const double desired_free_percentage = (double) free_ratio / 100.0;
const double desired_used_percentage = 1.0 - desired_free_percentage;
// We have to be careful here as these two calculations can overflow
// 32-bit size_t's.
double used_bytes_d = (double) used_bytes;
double desired_capacity_d = used_bytes_d / desired_used_percentage;
// Let's make sure that they are both under the max heap size, which
// by default will make it fit into a size_t.
double desired_capacity_upper_bound = (double) MaxHeapSize;
desired_capacity_d = MIN2(desired_capacity_d, desired_capacity_upper_bound);
// We can now safely turn it into size_t's.
return (size_t) desired_capacity_d;
}
size_t G1HeapSizingPolicy::full_collection_resize_amount(bool& expand) {
// Capacity, free and used after the GC counted as full regions to
// include the waste in the following calculations.
const size_t capacity_after_gc = _g1h->capacity();
const size_t used_after_gc = capacity_after_gc - _g1h->unused_committed_regions_in_bytes();
size_t minimum_desired_capacity = target_heap_capacity(used_after_gc, MinHeapFreeRatio);
size_t maximum_desired_capacity = target_heap_capacity(used_after_gc, MaxHeapFreeRatio);
// This assert only makes sense here, before we adjust them
// with respect to the min and max heap size.
assert(minimum_desired_capacity <= maximum_desired_capacity,
"minimum_desired_capacity = " SIZE_FORMAT ", "
"maximum_desired_capacity = " SIZE_FORMAT,
minimum_desired_capacity, maximum_desired_capacity);
// Should not be greater than the heap max size. No need to adjust
// it with respect to the heap min size as it's a lower bound (i.e.,
// we'll try to make the capacity larger than it, not smaller).
minimum_desired_capacity = MIN2(minimum_desired_capacity, MaxHeapSize);
// Should not be less than the heap min size. No need to adjust it
// with respect to the heap max size as it's an upper bound (i.e.,
// we'll try to make the capacity smaller than it, not greater).
maximum_desired_capacity = MAX2(maximum_desired_capacity, MinHeapSize);
// Don't expand unless it's significant; prefer expansion to shrinking.
if (capacity_after_gc < minimum_desired_capacity) {
size_t expand_bytes = minimum_desired_capacity - capacity_after_gc;
log_debug(gc, ergo, heap)("Attempt heap expansion (capacity lower than min desired capacity). "
"Capacity: " SIZE_FORMAT "B occupancy: " SIZE_FORMAT "B live: " SIZE_FORMAT "B "
"min_desired_capacity: " SIZE_FORMAT "B (" UINTX_FORMAT " %%)",
capacity_after_gc, used_after_gc, _g1h->used(), minimum_desired_capacity, MinHeapFreeRatio);
expand = true;
return expand_bytes;
// No expansion, now see if we want to shrink
} else if (capacity_after_gc > maximum_desired_capacity) {
// Capacity too large, compute shrinking size
size_t shrink_bytes = capacity_after_gc - maximum_desired_capacity;
log_debug(gc, ergo, heap)("Attempt heap shrinking (capacity higher than max desired capacity). "
"Capacity: " SIZE_FORMAT "B occupancy: " SIZE_FORMAT "B live: " SIZE_FORMAT "B "
"maximum_desired_capacity: " SIZE_FORMAT "B (" UINTX_FORMAT " %%)",
capacity_after_gc, used_after_gc, _g1h->used(), maximum_desired_capacity, MaxHeapFreeRatio);
expand = false;
return shrink_bytes;
}
expand = true; // Does not matter.
return 0;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. 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
@ -54,8 +54,11 @@ public:
// If an expansion would be appropriate, because recent GC overhead had
// exceeded the desired limit, return an amount to expand by.
size_t expansion_amount();
size_t young_collection_expansion_amount();
// Returns the amount of bytes to resize the heap; if expand is set, the heap
// should by expanded by that amount, shrunk otherwise.
size_t full_collection_resize_amount(bool& expand);
// Clear ratio tracking data used by expansion_amount().
void clear_ratio_check_data();