Print this page
JDK-8236073 G1: Use SoftMaxHeapSize to guide GC heuristics

@@ -30,10 +30,11 @@
 #include "gc/g1/g1CollectionSetCandidates.hpp"
 #include "gc/g1/g1ConcurrentMark.hpp"
 #include "gc/g1/g1ConcurrentMarkThread.inline.hpp"
 #include "gc/g1/g1ConcurrentRefine.hpp"
 #include "gc/g1/g1CollectionSetChooser.hpp"
+#include "gc/g1/g1HeapSizingPolicy.hpp"
 #include "gc/g1/g1HeterogeneousHeapPolicy.hpp"
 #include "gc/g1/g1HotCardCache.hpp"
 #include "gc/g1/g1IHOPControl.hpp"
 #include "gc/g1/g1GCPhaseTimes.hpp"
 #include "gc/g1/g1Policy.hpp"

@@ -74,10 +75,11 @@
   _pending_cards_at_prev_gc_end(0),
   _total_mutator_refined_cards(0),
   _total_concurrent_refined_cards(0),
   _total_concurrent_refinement_time(),
   _bytes_allocated_in_old_since_last_gc(0),
+  _minimum_desired_bytes_after_last_cm(0),
   _initial_mark_to_mixed(),
   _collection_set(NULL),
   _g1h(NULL),
   _phase_times(new G1GCPhaseTimes(gc_timer, ParallelGCThreads)),
   _mark_remark_start_sec(0),

@@ -1093,10 +1095,25 @@
       log_debug(gc, ergo)("Do not initiate concurrent cycle (concurrent cycle already in progress)");
     }
   }
 }
 
+void G1Policy::determine_desired_bytes_after_concurrent_mark() {
+  size_t cur_used_bytes = _g1h->non_young_capacity_bytes();
+
+  size_t overall_target_capacity = _g1h->heap_sizing_policy()->target_heap_capacity(cur_used_bytes, MinHeapFreeRatio);
+
+  size_t desired_bytes_after_concurrent_mark = _g1h->policy()->desired_bytes_after_concurrent_mark(cur_used_bytes);
+
+  _minimum_desired_bytes_after_last_cm = MIN2(desired_bytes_after_concurrent_mark, overall_target_capacity);
+
+  log_debug(gc, ergo, heap)("Expansion amount after remark used: " SIZE_FORMAT " "
+                            "minimum_desired_capacity " SIZE_FORMAT " desired_bytes_after_concurrent_mark: " SIZE_FORMAT " "
+                            "minimum_desired_bytes_after_concurrent_mark " SIZE_FORMAT,
+                            cur_used_bytes, overall_target_capacity, desired_bytes_after_concurrent_mark, _minimum_desired_bytes_after_last_cm);
+}
+
 void G1Policy::record_concurrent_mark_cleanup_end() {
   G1CollectionSetCandidates* candidates = G1CollectionSetChooser::build(_g1h->workers(), _g1h->num_regions());
   _collection_set->set_candidates(candidates);
 
   bool mixed_gc_pending = next_gc_should_be_mixed("request mixed gcs", "request young-only gcs");

@@ -1105,10 +1122,12 @@
     abort_time_to_mixed_tracking();
   }
   collector_state()->set_in_young_gc_before_mixed(mixed_gc_pending);
   collector_state()->set_mark_or_rebuild_in_progress(false);
 
+  determine_desired_bytes_after_concurrent_mark();
+
   double end_sec = os::elapsedTime();
   double elapsed_time_ms = (end_sec - _mark_cleanup_start_sec) * 1000.0;
   _analytics->report_concurrent_mark_cleanup_times_ms(elapsed_time_ms);
   _analytics->append_prev_collection_pause_end_ms(elapsed_time_ms);
 

@@ -1197,26 +1216,32 @@
 
 bool G1Policy::next_gc_should_be_mixed(const char* true_action_str,
                                        const char* false_action_str) const {
   G1CollectionSetCandidates* candidates = _collection_set->candidates();
 
-  if (candidates->is_empty()) {
+  if (candidates == NULL || candidates->is_empty()) {
+    if (false_action_str != NULL) {
     log_debug(gc, ergo)("%s (candidate old regions not available)", false_action_str);
+    }
     return false;
   }
 
   // Is the amount of uncollected reclaimable space above G1HeapWastePercent?
   size_t reclaimable_bytes = candidates->remaining_reclaimable_bytes();
   double reclaimable_percent = reclaimable_bytes_percent(reclaimable_bytes);
   double threshold = (double) G1HeapWastePercent;
   if (reclaimable_percent <= threshold) {
+    if (false_action_str != NULL) {
     log_debug(gc, ergo)("%s (reclaimable percentage not over threshold). candidate old regions: %u reclaimable: " SIZE_FORMAT " (%1.2f) threshold: " UINTX_FORMAT,
                         false_action_str, candidates->num_remaining(), reclaimable_bytes, reclaimable_percent, G1HeapWastePercent);
+    }
     return false;
   }
+  if (true_action_str != NULL) {
   log_debug(gc, ergo)("%s (candidate old regions available). candidate old regions: %u reclaimable: " SIZE_FORMAT " (%1.2f) threshold: " UINTX_FORMAT,
                       true_action_str, candidates->num_remaining(), reclaimable_bytes, reclaimable_percent, G1HeapWastePercent);
+  }
   return true;
 }
 
 uint G1Policy::calc_min_old_cset_length() const {
   // The min old CSet region bound is based on the maximum desired

@@ -1409,5 +1434,14 @@
   // Don't clear the survivor list handles until the start of
   // the next evacuation pause - we need it in order to re-tag
   // the survivor regions from this evacuation pause as 'young'
   // at the start of the next.
 }
+
+size_t G1Policy::desired_bytes_after_concurrent_mark(size_t used_bytes) {
+  size_t minimum_desired_buffer_size = _ihop_control->predict_unrestrained_buffer_size();
+  if (minimum_desired_buffer_size != 0) {
+    return minimum_desired_buffer_size;
+  } else {
+    return _young_list_max_length * HeapRegion::GrainBytes + _reserve_regions * HeapRegion::GrainBytes + used_bytes;
+  }
+}