8152724: Sum of eden before GC and current survivor capacity may be larger than heap size

Limit the maximum survivor size for a given GC to the remaining number of free regions.

Reviewed-by: sjohanss, sangheki
This commit is contained in:
Thomas Schatzl 2018-12-12 12:00:02 +01:00
parent 597c61458e
commit 7223ed2205
5 changed files with 85 additions and 10 deletions

View File

@ -1026,6 +1026,9 @@ public:
// The number of regions that are completely free.
uint num_free_regions() const { return _hrm.num_free_regions(); }
// The number of regions that can be allocated into.
uint num_free_or_available_regions() const { return num_free_regions() + _hrm.available(); }
MemoryUsage get_auxiliary_data_memory_usage() const {
return _hrm.get_auxiliary_data_memory_usage();
}

View File

@ -89,7 +89,7 @@ void G1HeapTransition::print() {
Data after(_g1_heap);
size_t eden_capacity_length_after_gc = _g1_heap->g1_policy()->young_list_target_length() - after._survivor_length;
size_t survivor_capacity_length_after_gc = _g1_heap->g1_policy()->max_survivor_regions();
size_t survivor_capacity_length_before_gc = _g1_heap->g1_policy()->max_survivor_regions();
DetailedUsage usage;
if (log_is_enabled(Trace, gc, heap)) {
@ -112,7 +112,7 @@ void G1HeapTransition::print() {
log_trace(gc, heap)(" Used: 0K, Waste: 0K");
log_info(gc, heap)("Survivor regions: " SIZE_FORMAT "->" SIZE_FORMAT "(" SIZE_FORMAT ")",
_before._survivor_length, after._survivor_length, survivor_capacity_length_after_gc);
_before._survivor_length, after._survivor_length, survivor_capacity_length_before_gc);
log_trace(gc, heap)(" Used: " SIZE_FORMAT "K, Waste: " SIZE_FORMAT "K",
usage._survivor_used / K, ((after._survivor_length * HeapRegion::GrainBytes) - usage._survivor_used) / K);

View File

@ -470,6 +470,10 @@ void G1Policy::record_collection_pause_start(double start_time_sec) {
// every time we calculate / recalculate the target young length.
update_survivors_policy();
assert(max_survivor_regions() + _g1h->num_used_regions() <= _g1h->max_regions(),
"Maximum survivor regions %u plus used regions %u exceeds max regions %u",
max_survivor_regions(), _g1h->num_used_regions(), _g1h->max_regions());
assert(_g1h->used() == _g1h->recalculate_used(),
"sanity, used: " SIZE_FORMAT " recalculate_used: " SIZE_FORMAT,
_g1h->used(), _g1h->recalculate_used());
@ -899,8 +903,8 @@ bool G1Policy::adaptive_young_list_length() const {
return _young_gen_sizer.adaptive_young_list_length();
}
size_t G1Policy::desired_survivor_size() const {
size_t const survivor_capacity = HeapRegion::GrainWords * _max_survivor_regions;
size_t G1Policy::desired_survivor_size(uint max_regions) const {
size_t const survivor_capacity = HeapRegion::GrainWords * max_regions;
return (size_t)((((double)survivor_capacity) * TargetSurvivorRatio) / 100);
}
@ -927,15 +931,22 @@ void G1Policy::update_max_gc_locker_expansion() {
void G1Policy::update_survivors_policy() {
double max_survivor_regions_d =
(double) _young_list_target_length / (double) SurvivorRatio;
// We use ceiling so that if max_survivor_regions_d is > 0.0 (but
// smaller than 1.0) we'll get 1.
_max_survivor_regions = (uint) ceil(max_survivor_regions_d);
_tenuring_threshold = _survivors_age_table.compute_tenuring_threshold(desired_survivor_size());
// Calculate desired survivor size based on desired max survivor regions (unconstrained
// by remaining heap). Otherwise we may cause undesired promotions as we are
// already getting close to end of the heap, impacting performance even more.
uint const desired_max_survivor_regions = ceil(max_survivor_regions_d);
size_t const survivor_size = desired_survivor_size(desired_max_survivor_regions);
_tenuring_threshold = _survivors_age_table.compute_tenuring_threshold(survivor_size);
if (UsePerfData) {
_policy_counters->tenuring_threshold()->set_value(_tenuring_threshold);
_policy_counters->desired_survivor_size()->set_value(desired_survivor_size() * oopSize);
_policy_counters->desired_survivor_size()->set_value(survivor_size * oopSize);
}
// The real maximum survivor size is bounded by the number of regions that can
// be allocated into.
_max_survivor_regions = MIN2(desired_max_survivor_regions,
_g1h->num_free_or_available_regions());
}
bool G1Policy::force_initial_mark_if_outside_cycle(GCCause::Cause gc_cause) {

View File

@ -399,7 +399,7 @@ private:
AgeTable _survivors_age_table;
size_t desired_survivor_size() const;
size_t desired_survivor_size(uint max_regions) const;
public:
// Fraction used when predicting how many optional regions to include in
// the CSet. This fraction of the available time is used for optional regions,

View File

@ -0,0 +1,61 @@
/*
* Copyright (c) 2018, 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
* 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 TestEdenSurvivorLessThanMax
* @bug 8152724
* @summary Check that G1 eden plus survivor max capacity after GC does not exceed maximum number of regions.
* @requires vm.gc.G1
* @key gc
* @library /test/lib
* @build sun.hotspot.WhiteBox
* @run driver ClassFileInstaller sun.hotspot.WhiteBox
* @run main/othervm -Xbootclasspath/a:. -Xlog:gc+heap=debug -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC -Xmx64M -Xms64M -Xmn50M -XX:SurvivorRatio=1 TestEdenSurvivorLessThanMax
*/
import sun.hotspot.WhiteBox;
// The test fills the heap in a way that previous to 8152724 the maximum number of survivor regions
// for that young gc was higher than there was free space left which is impossible.
public class TestEdenSurvivorLessThanMax {
private static final long BYTES_TO_FILL = 50 * 1024 * 1024;
private static final WhiteBox WB = WhiteBox.getWhiteBox();
public static void main(String[] args) throws Exception {
Object o = new int[100];
long objSize = WB.getObjectSize(o);
// Fill eden to approximately ~90%.
int numObjs = (int)((BYTES_TO_FILL / objSize) * 9 / 10);
for (int i = 0; i < numObjs; i++) {
o = new int[100];
}
WB.youngGC();
System.out.println(o.toString());
}
}