diff -r ec2a8bd1615b -r 1805414a18bc hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp --- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp Thu Dec 10 13:38:18 2015 -0500 +++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp Thu Dec 10 18:55:58 2015 +0000 @@ -191,6 +191,7 @@ _recent_prev_end_times_for_all_gcs_sec->add(os::elapsedTime()); _prev_collection_pause_end_ms = os::elapsedTime() * 1000.0; + clear_ratio_check_data(); _phase_times = new G1GCPhaseTimes(_parallel_gc_threads); @@ -1080,6 +1081,14 @@ _recent_avg_pause_time_ratio = 1.0; } } + + // Compute the ratio of just this last pause time to the entire time range stored + // in the vectors. Comparing this pause to the entire range, rather than only the + // most recent interval, has the effect of smoothing over a possible transient 'burst' + // of more frequent pauses that don't really reflect a change in heap occupancy. + // This reduces the likelihood of a needless heap expansion being triggered. + _last_pause_time_ratio = + (pause_time_ms * _recent_prev_end_times_for_all_gcs_sec->num()) / interval_ms; } bool new_in_marking_window = collector_state()->in_marking_window(); @@ -1597,41 +1606,124 @@ _prev_collection_pause_end_ms = end_time_sec * 1000.0; } -size_t G1CollectorPolicy::expansion_amount() const { +void G1CollectorPolicy::clear_ratio_check_data() { + _ratio_over_threshold_count = 0; + _ratio_over_threshold_sum = 0.0; + _pauses_since_start = 0; +} + +size_t G1CollectorPolicy::expansion_amount() { double recent_gc_overhead = recent_avg_pause_time_ratio() * 100.0; + double last_gc_overhead = _last_pause_time_ratio * 100.0; double threshold = _gc_overhead_perc; - if (recent_gc_overhead > threshold) { - // We will double the existing space, or take - // G1ExpandByPercentOfAvailable % of the available expansion - // space, whichever is smaller, bounded below by a minimum - // expansion (unless that's all that's left.) - const size_t min_expand_bytes = 1*M; + size_t expand_bytes = 0; + + // If the heap is at less than half its maximum size, scale the threshold down, + // to a limit of 1. Thus the smaller the heap is, the more likely it is to expand, + // though the scaling code will likely keep the increase small. + if (_g1->capacity() <= _g1->max_capacity() / 2) { + threshold *= (double)_g1->capacity() / (double)(_g1->max_capacity() / 2); + threshold = MAX2(threshold, 1.0); + } + + // If the last GC time ratio is over the threshold, increment the count of + // times it has been exceeded, and add this ratio to the sum of exceeded + // ratios. + if (last_gc_overhead > threshold) { + _ratio_over_threshold_count++; + _ratio_over_threshold_sum += last_gc_overhead; + } + + // Check if we've had enough GC time ratio checks that were over the + // threshold to trigger an expansion. We'll also expand if we've + // reached the end of the history buffer and the average of all entries + // is still over the threshold. This indicates a smaller number of GCs were + // long enough to make the average exceed the threshold. + bool filled_history_buffer = _pauses_since_start == NumPrevPausesForHeuristics; + if ((_ratio_over_threshold_count == MinOverThresholdForGrowth) || + (filled_history_buffer && (recent_gc_overhead > threshold))) { + size_t min_expand_bytes = HeapRegion::GrainBytes; size_t reserved_bytes = _g1->max_capacity(); size_t committed_bytes = _g1->capacity(); size_t uncommitted_bytes = reserved_bytes - committed_bytes; - size_t expand_bytes; size_t expand_bytes_via_pct = uncommitted_bytes * G1ExpandByPercentOfAvailable / 100; - expand_bytes = MIN2(expand_bytes_via_pct, committed_bytes); - expand_bytes = MAX2(expand_bytes, min_expand_bytes); - expand_bytes = MIN2(expand_bytes, uncommitted_bytes); + double scale_factor = 1.0; + + // If the current size is less than 1/4 of the Initial heap size, expand + // by half of the delta between the current and Initial sizes. IE, grow + // back quickly. + // + // Otherwise, take the current size, or G1ExpandByPercentOfAvailable % of + // the available expansion space, whichever is smaller, as the base + // expansion size. Then possibly scale this size according to how much the + // threshold has (on average) been exceeded by. If the delta is small + // (less than the StartScaleDownAt value), scale the size down linearly, but + // not by less than MinScaleDownFactor. If the delta is large (greater than + // the StartScaleUpAt value), scale up, but adding no more than MaxScaleUpFactor + // times the base size. The scaling will be linear in the range from + // StartScaleUpAt to (StartScaleUpAt + ScaleUpRange). In other words, + // ScaleUpRange sets the rate of scaling up. + if (committed_bytes < InitialHeapSize / 4) { + expand_bytes = (InitialHeapSize - committed_bytes) / 2; + } else { + double const MinScaleDownFactor = 0.2; + double const MaxScaleUpFactor = 2; + double const StartScaleDownAt = _gc_overhead_perc; + double const StartScaleUpAt = _gc_overhead_perc * 1.5; + double const ScaleUpRange = _gc_overhead_perc * 2.0; + + double ratio_delta; + if (filled_history_buffer) { + ratio_delta = recent_gc_overhead - threshold; + } else { + ratio_delta = (_ratio_over_threshold_sum/_ratio_over_threshold_count) - threshold; + } + + expand_bytes = MIN2(expand_bytes_via_pct, committed_bytes); + if (ratio_delta < StartScaleDownAt) { + scale_factor = ratio_delta / StartScaleDownAt; + scale_factor = MAX2(scale_factor, MinScaleDownFactor); + } else if (ratio_delta > StartScaleUpAt) { + scale_factor = 1 + ((ratio_delta - StartScaleUpAt) / ScaleUpRange); + scale_factor = MIN2(scale_factor, MaxScaleUpFactor); + } + } ergo_verbose5(ErgoHeapSizing, "attempt heap expansion", ergo_format_reason("recent GC overhead higher than " "threshold after GC") ergo_format_perc("recent GC overhead") - ergo_format_perc("threshold") + ergo_format_perc("current threshold") ergo_format_byte("uncommitted") - ergo_format_byte_perc("calculated expansion amount"), + ergo_format_byte_perc("base expansion amount and scale"), recent_gc_overhead, threshold, uncommitted_bytes, - expand_bytes_via_pct, (double) G1ExpandByPercentOfAvailable); + expand_bytes, scale_factor * 100); + + expand_bytes = static_cast(expand_bytes * scale_factor); + + // Ensure the expansion size is at least the minimum growth amount + // and at most the remaining uncommitted byte size. + expand_bytes = MAX2(expand_bytes, min_expand_bytes); + expand_bytes = MIN2(expand_bytes, uncommitted_bytes); - return expand_bytes; + clear_ratio_check_data(); } else { - return 0; + // An expansion was not triggered. If we've started counting, increment + // the number of checks we've made in the current window. If we've + // reached the end of the window without resizing, clear the counters to + // start again the next time we see a ratio above the threshold. + if (_ratio_over_threshold_count > 0) { + _pauses_since_start++; + if (_pauses_since_start > NumPrevPausesForHeuristics) { + clear_ratio_check_data(); + } + } } + + return expand_bytes; } void G1CollectorPolicy::print_tracing_info() const {