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:
parent
597c61458e
commit
7223ed2205
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
|
61
test/hotspot/jtreg/gc/g1/TestEdenSurvivorLessThanMax.java
Normal file
61
test/hotspot/jtreg/gc/g1/TestEdenSurvivorLessThanMax.java
Normal 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());
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user