hotspot/src/share/vm/memory/collectorPolicy.cpp
changeset 23851 60303358c862
parent 23224 b156569bc190
child 24353 148147d21135
--- a/hotspot/src/share/vm/memory/collectorPolicy.cpp	Wed Apr 02 14:17:34 2014 +0200
+++ b/hotspot/src/share/vm/memory/collectorPolicy.cpp	Wed Mar 19 17:08:03 2014 +0100
@@ -257,6 +257,12 @@
   assert(_min_gen0_size % _gen_alignment == 0, "_min_gen0_size alignment");
   assert(_initial_gen0_size % _gen_alignment == 0, "_initial_gen0_size alignment");
   assert(_max_gen0_size % _gen_alignment == 0, "_max_gen0_size alignment");
+  assert(_min_gen0_size <= bound_minus_alignment(_min_gen0_size, _min_heap_byte_size),
+      "Ergonomics made minimum young generation larger than minimum heap");
+  assert(_initial_gen0_size <=  bound_minus_alignment(_initial_gen0_size, _initial_heap_byte_size),
+      "Ergonomics made initial young generation larger than initial heap");
+  assert(_max_gen0_size <= bound_minus_alignment(_max_gen0_size, _max_heap_byte_size),
+      "Ergonomics made maximum young generation lager than maximum heap");
 }
 
 void TwoGenerationCollectorPolicy::assert_size_info() {
@@ -267,6 +273,9 @@
   assert(_max_gen1_size % _gen_alignment == 0, "_max_gen1_size alignment");
   assert(_initial_gen1_size % _gen_alignment == 0, "_initial_gen1_size alignment");
   assert(_max_heap_byte_size <= (_max_gen0_size + _max_gen1_size), "Total maximum heap sizes must be sum of generation maximum sizes");
+  assert(_min_gen0_size + _min_gen1_size <= _min_heap_byte_size, "Minimum generation sizes exceed minimum heap size");
+  assert(_initial_gen0_size + _initial_gen1_size == _initial_heap_byte_size, "Initial generation sizes should match initial heap size");
+  assert(_max_gen0_size + _max_gen1_size == _max_heap_byte_size, "Maximum generation sizes should match maximum heap size");
 }
 #endif // ASSERT
 
@@ -303,20 +312,26 @@
     }
   }
 
+  // Make sure NewSize allows an old generation to fit even if set on the command line
+  if (FLAG_IS_CMDLINE(NewSize) && NewSize >= _initial_heap_byte_size) {
+    warning("NewSize was set larger than initial heap size, will use initial heap size.");
+    NewSize = bound_minus_alignment(NewSize, _initial_heap_byte_size);
+  }
+
   // Now take the actual NewSize into account. We will silently increase NewSize
   // if the user specified a smaller or unaligned value.
-  smallest_new_size = MAX2(smallest_new_size, (uintx)align_size_down(NewSize, _gen_alignment));
-  if (smallest_new_size != NewSize) {
+  uintx bounded_new_size = bound_minus_alignment(NewSize, MaxHeapSize);
+  bounded_new_size = MAX2(smallest_new_size, (uintx)align_size_down(bounded_new_size, _gen_alignment));
+  if (bounded_new_size != NewSize) {
     // Do not use FLAG_SET_ERGO to update NewSize here, since this will override
     // if NewSize was set on the command line or not. This information is needed
     // later when setting the initial and minimum young generation size.
-    NewSize = smallest_new_size;
+    NewSize = bounded_new_size;
   }
+  _min_gen0_size = smallest_new_size;
   _initial_gen0_size = NewSize;
 
   if (!FLAG_IS_DEFAULT(MaxNewSize)) {
-    uintx min_new_size = MAX2(_gen_alignment, _min_gen0_size);
-
     if (MaxNewSize >= MaxHeapSize) {
       // Make sure there is room for an old generation
       uintx smaller_max_new_size = MaxHeapSize - _gen_alignment;
@@ -330,8 +345,8 @@
         FLAG_SET_ERGO(uintx, NewSize, MaxNewSize);
         _initial_gen0_size = NewSize;
       }
-    } else if (MaxNewSize < min_new_size) {
-      FLAG_SET_ERGO(uintx, MaxNewSize, min_new_size);
+    } else if (MaxNewSize < _initial_gen0_size) {
+      FLAG_SET_ERGO(uintx, MaxNewSize, _initial_gen0_size);
     } else if (!is_size_aligned(MaxNewSize, _gen_alignment)) {
       FLAG_SET_ERGO(uintx, MaxNewSize, align_size_down(MaxNewSize, _gen_alignment));
     }
@@ -361,7 +376,9 @@
   GenCollectorPolicy::initialize_flags();
 
   if (!is_size_aligned(OldSize, _gen_alignment)) {
-    FLAG_SET_ERGO(uintx, OldSize, align_size_down(OldSize, _gen_alignment));
+    // Setting OldSize directly to preserve information about the possible
+    // setting of OldSize on the command line.
+    OldSize = align_size_down(OldSize, _gen_alignment);
   }
 
   if (FLAG_IS_CMDLINE(OldSize) && FLAG_IS_DEFAULT(MaxHeapSize)) {
@@ -400,6 +417,20 @@
     }
   }
 
+  // Update NewSize, if possible, to avoid sizing gen0 to small when only
+  // OldSize is set on the command line.
+  if (FLAG_IS_CMDLINE(OldSize) && !FLAG_IS_CMDLINE(NewSize)) {
+    if (OldSize < _initial_heap_byte_size) {
+      size_t new_size = _initial_heap_byte_size - OldSize;
+      // Need to compare against the flag value for max since _max_gen0_size
+      // might not have been set yet.
+      if (new_size >= _min_gen0_size && new_size <= MaxNewSize) {
+        FLAG_SET_ERGO(uintx, NewSize, new_size);
+        _initial_gen0_size = NewSize;
+      }
+    }
+  }
+
   always_do_update_barrier = UseConcMarkSweepGC;
 
   DEBUG_ONLY(TwoGenerationCollectorPolicy::assert_flags();)
@@ -441,57 +472,37 @@
   // Given the maximum gen0 size, determine the initial and
   // minimum gen0 sizes.
 
-  if (_max_heap_byte_size == _min_heap_byte_size) {
-    // The maximum and minimum heap sizes are the same so the generations
-    // minimum and initial must be the same as its maximum.
-    _min_gen0_size = max_new_size;
-    _initial_gen0_size = max_new_size;
-    _max_gen0_size = max_new_size;
+  if (_max_heap_byte_size == _initial_heap_byte_size) {
+    // The maxium and initial heap sizes are the same so the generation's
+    // initial size must be the same as it maximum size. Use NewSize as the
+    // size if set on command line.
+    size_t fixed_young_size = FLAG_IS_CMDLINE(NewSize) ? NewSize : max_new_size;
+
+    _initial_gen0_size = fixed_young_size;
+    _max_gen0_size = fixed_young_size;
+
+    // Also update the minimum size if min == initial == max.
+    if (_max_heap_byte_size == _min_heap_byte_size) {
+      _min_gen0_size = fixed_young_size;
+    }
   } else {
     size_t desired_new_size = 0;
     if (FLAG_IS_CMDLINE(NewSize)) {
-      // If NewSize is set on the command line, we must use it as
-      // the initial size and it also makes sense to use it as the
-      // lower limit.
-      _min_gen0_size = NewSize;
-      desired_new_size = NewSize;
-      max_new_size = MAX2(max_new_size, NewSize);
-    } else if (FLAG_IS_ERGO(NewSize)) {
-      // If NewSize is set ergonomically, we should use it as a lower
-      // limit, but use NewRatio to calculate the initial size.
-      _min_gen0_size = NewSize;
+      // If NewSize is set on the command line, we should use it as
+      // the initial size, but make sure it is within the heap bounds.
       desired_new_size =
-        MAX2(scale_by_NewRatio_aligned(_initial_heap_byte_size), NewSize);
-      max_new_size = MAX2(max_new_size, NewSize);
+        MIN2(max_new_size, bound_minus_alignment(NewSize, _initial_heap_byte_size));
+      _min_gen0_size = bound_minus_alignment(desired_new_size, _min_heap_byte_size);
     } else {
-      // For the case where NewSize is the default, use NewRatio
-      // to size the minimum and initial generation sizes.
-      // Use the default NewSize as the floor for these values.  If
-      // NewRatio is overly large, the resulting sizes can be too small.
-      _min_gen0_size = MAX2(scale_by_NewRatio_aligned(_min_heap_byte_size), NewSize);
+      // For the case where NewSize is not set on the command line, use
+      // NewRatio to size the initial generation size. Use the current
+      // NewSize as the floor, because if NewRatio is overly large, the resulting
+      // size can be too small.
       desired_new_size =
-        MAX2(scale_by_NewRatio_aligned(_initial_heap_byte_size), NewSize);
+        MIN2(max_new_size, MAX2(scale_by_NewRatio_aligned(_initial_heap_byte_size), NewSize));
     }
-
-    assert(_min_gen0_size > 0, "Sanity check");
     _initial_gen0_size = desired_new_size;
     _max_gen0_size = max_new_size;
-
-    // At this point the desirable initial and minimum sizes have been
-    // determined without regard to the maximum sizes.
-
-    // Bound the sizes by the corresponding overall heap sizes.
-    _min_gen0_size = bound_minus_alignment(_min_gen0_size, _min_heap_byte_size);
-    _initial_gen0_size = bound_minus_alignment(_initial_gen0_size, _initial_heap_byte_size);
-    _max_gen0_size = bound_minus_alignment(_max_gen0_size, _max_heap_byte_size);
-
-    // At this point all three sizes have been checked against the
-    // maximum sizes but have not been checked for consistency among the three.
-
-    // Final check min <= initial <= max
-    _min_gen0_size = MIN2(_min_gen0_size, _max_gen0_size);
-    _initial_gen0_size = MAX2(MIN2(_initial_gen0_size, _max_gen0_size), _min_gen0_size);
-    _min_gen0_size = MIN2(_min_gen0_size, _initial_gen0_size);
   }
 
   // Write back to flags if necessary.
@@ -512,33 +523,6 @@
   DEBUG_ONLY(GenCollectorPolicy::assert_size_info();)
 }
 
-// Call this method during the sizing of the gen1 to make
-// adjustments to gen0 because of gen1 sizing policy.  gen0 initially has
-// the most freedom in sizing because it is done before the
-// policy for gen1 is applied.  Once gen1 policies have been applied,
-// there may be conflicts in the shape of the heap and this method
-// is used to make the needed adjustments.  The application of the
-// policies could be more sophisticated (iterative for example) but
-// keeping it simple also seems a worthwhile goal.
-bool TwoGenerationCollectorPolicy::adjust_gen0_sizes(size_t* gen0_size_ptr,
-                                                     size_t* gen1_size_ptr,
-                                                     const size_t heap_size) {
-  bool result = false;
-
-  if ((*gen0_size_ptr + *gen1_size_ptr) > heap_size) {
-    uintx smallest_new_size = young_gen_size_lower_bound();
-    if ((heap_size < (*gen0_size_ptr + _min_gen1_size)) &&
-        (heap_size >= _min_gen1_size + smallest_new_size)) {
-      // Adjust gen0 down to accommodate _min_gen1_size
-      *gen0_size_ptr = align_size_down_bounded(heap_size - _min_gen1_size, _gen_alignment);
-      result = true;
-    } else {
-      *gen1_size_ptr = align_size_down_bounded(heap_size - *gen0_size_ptr, _gen_alignment);
-    }
-  }
-  return result;
-}
-
 // Minimum sizes of the generations may be different than
 // the initial sizes.  An inconsistency is permitted here
 // in the total size that can be specified explicitly by
@@ -564,57 +548,64 @@
     // with the overall heap size).  In either case make
     // the minimum, maximum and initial sizes consistent
     // with the gen0 sizes and the overall heap sizes.
-    _min_gen1_size = MAX2(_min_heap_byte_size - _min_gen0_size, _gen_alignment);
-    _initial_gen1_size = MAX2(_initial_heap_byte_size - _initial_gen0_size, _gen_alignment);
+    _min_gen1_size = _gen_alignment;
+    _initial_gen1_size = MIN2(_max_gen1_size, MAX2(_initial_heap_byte_size - _initial_gen0_size, _min_gen1_size));
     // _max_gen1_size has already been made consistent above
     FLAG_SET_ERGO(uintx, OldSize, _initial_gen1_size);
   } else {
-    // OldSize has been explicitly set on the command line. Use the
-    // OldSize and then determine the consequences.
-    _min_gen1_size = MIN2(OldSize, _min_heap_byte_size - _min_gen0_size);
-    _initial_gen1_size = OldSize;
-
+    // OldSize has been explicitly set on the command line. Use it
+    // for the initial size but make sure the minimum allow a young
+    // generation to fit as well.
     // If the user has explicitly set an OldSize that is inconsistent
     // with other command line flags, issue a warning.
     // The generation minimums and the overall heap minimum should
     // be within one generation alignment.
-    if ((_min_gen1_size + _min_gen0_size + _gen_alignment) < _min_heap_byte_size) {
-      warning("Inconsistency between minimum heap size and minimum "
-              "generation sizes: using minimum heap = " SIZE_FORMAT,
-              _min_heap_byte_size);
-    }
     if (OldSize > _max_gen1_size) {
       warning("Inconsistency between maximum heap size and maximum "
-              "generation sizes: using maximum heap = " SIZE_FORMAT
-              " -XX:OldSize flag is being ignored",
-              _max_heap_byte_size);
+          "generation sizes: using maximum heap = " SIZE_FORMAT
+          " -XX:OldSize flag is being ignored",
+          _max_heap_byte_size);
+      FLAG_SET_ERGO(uintx, OldSize, _max_gen1_size);
     }
-    // If there is an inconsistency between the OldSize and the minimum and/or
-    // initial size of gen0, since OldSize was explicitly set, OldSize wins.
-    if (adjust_gen0_sizes(&_min_gen0_size, &_min_gen1_size, _min_heap_byte_size)) {
-      if (PrintGCDetails && Verbose) {
-        gclog_or_tty->print_cr("2: Minimum gen0 " SIZE_FORMAT "  Initial gen0 "
-              SIZE_FORMAT "  Maximum gen0 " SIZE_FORMAT,
-              _min_gen0_size, _initial_gen0_size, _max_gen0_size);
-      }
+
+    _min_gen1_size = MIN2(OldSize, _min_heap_byte_size - _min_gen0_size);
+    _initial_gen1_size = OldSize;
+  }
+
+  // The initial generation sizes should match the initial heap size,
+  // if not issue a warning and resize the generations. This behavior
+  // differs from JDK8 where the generation sizes have higher priority
+  // than the initial heap size.
+  if ((_initial_gen1_size + _initial_gen0_size) != _initial_heap_byte_size) {
+    warning("Inconsistency between generation sizes and heap size, resizing "
+            "the generations to fit the heap.");
+
+    size_t desired_gen0_size = _initial_heap_byte_size - _initial_gen1_size;
+    if (_initial_heap_byte_size < _initial_gen1_size) {
+      // Old want all memory, use minimum for young and rest for old
+      _initial_gen0_size = _min_gen0_size;
+      _initial_gen1_size = _initial_heap_byte_size - _min_gen0_size;
+    } else if (desired_gen0_size > _max_gen0_size) {
+      // Need to increase both young and old generation
+      _initial_gen0_size = _max_gen0_size;
+      _initial_gen1_size = _initial_heap_byte_size - _max_gen0_size;
+    } else if (desired_gen0_size < _min_gen0_size) {
+      // Need to decrease both young and old generation
+      _initial_gen0_size = _min_gen0_size;
+      _initial_gen1_size = _initial_heap_byte_size - _min_gen0_size;
+    } else {
+      // The young generation boundaries allow us to only update the
+      // young generation.
+      _initial_gen0_size = desired_gen0_size;
     }
-    // The same as above for the old gen initial size.
-    if (adjust_gen0_sizes(&_initial_gen0_size, &_initial_gen1_size,
-                          _initial_heap_byte_size)) {
-      if (PrintGCDetails && Verbose) {
-        gclog_or_tty->print_cr("3: Minimum gen0 " SIZE_FORMAT "  Initial gen0 "
-          SIZE_FORMAT "  Maximum gen0 " SIZE_FORMAT,
-          _min_gen0_size, _initial_gen0_size, _max_gen0_size);
-      }
+
+    if (PrintGCDetails && Verbose) {
+      gclog_or_tty->print_cr("2: Minimum gen0 " SIZE_FORMAT "  Initial gen0 "
+        SIZE_FORMAT "  Maximum gen0 " SIZE_FORMAT,
+        _min_gen0_size, _initial_gen0_size, _max_gen0_size);
     }
   }
 
-  _min_gen1_size = MIN2(_min_gen1_size, _max_gen1_size);
-
-  // Make sure that min gen1 <= initial gen1 <= max gen1.
-  _initial_gen1_size = MAX2(_initial_gen1_size, _min_gen1_size);
-  _initial_gen1_size = MIN2(_initial_gen1_size, _max_gen1_size);
-
   // Write back to flags if necessary
   if (NewSize != _initial_gen0_size) {
     FLAG_SET_ERGO(uintx, NewSize, _initial_gen0_size);
@@ -994,56 +985,88 @@
 // verify that there are some basic rules for NewSize honored by the policies.
 class TestGenCollectorPolicy {
 public:
-  static void test() {
+  static void test_new_size() {
     size_t flag_value;
 
     save_flags();
 
-    // Set some limits that makes the math simple.
-    FLAG_SET_ERGO(uintx, MaxHeapSize, 180 * M);
-    FLAG_SET_ERGO(uintx, InitialHeapSize, 120 * M);
-    Arguments::set_min_heap_size(40 * M);
-
     // If NewSize is set on the command line, it should be used
     // for both min and initial young size if less than min heap.
     flag_value = 20 * M;
+    set_basic_flag_values();
     FLAG_SET_CMDLINE(uintx, NewSize, flag_value);
-    verify_min(flag_value);
-    verify_initial(flag_value);
+    verify_gen0_min(flag_value);
+
+    set_basic_flag_values();
+    FLAG_SET_CMDLINE(uintx, NewSize, flag_value);
+    verify_gen0_initial(flag_value);
 
     // If NewSize is set on command line, but is larger than the min
     // heap size, it should only be used for initial young size.
     flag_value = 80 * M;
+    set_basic_flag_values();
     FLAG_SET_CMDLINE(uintx, NewSize, flag_value);
-    verify_initial(flag_value);
+    verify_gen0_initial(flag_value);
 
     // If NewSize has been ergonomically set, the collector policy
     // should use it for min but calculate the initial young size
     // using NewRatio.
     flag_value = 20 * M;
+    set_basic_flag_values();
     FLAG_SET_ERGO(uintx, NewSize, flag_value);
-    verify_min(flag_value);
-    verify_scaled_initial(InitialHeapSize);
+    verify_gen0_min(flag_value);
+
+    set_basic_flag_values();
+    FLAG_SET_ERGO(uintx, NewSize, flag_value);
+    verify_scaled_gen0_initial(InitialHeapSize);
 
     restore_flags();
+  }
+
+  static void test_old_size() {
+      size_t flag_value;
+
+      save_flags();
+
+      // If OldSize is set on the command line, it should be used
+      // for both min and initial old size if less than min heap.
+      flag_value = 20 * M;
+      set_basic_flag_values();
+      FLAG_SET_CMDLINE(uintx, OldSize, flag_value);
+      verify_gen1_min(flag_value);
+
+      set_basic_flag_values();
+      FLAG_SET_CMDLINE(uintx, OldSize, flag_value);
+      verify_gen1_initial(flag_value);
+
+      // If MaxNewSize is large, the maximum OldSize will be less than
+      // what's requested on the command line and it should be reset
+      // ergonomically.
+      flag_value = 30 * M;
+      set_basic_flag_values();
+      FLAG_SET_CMDLINE(uintx, OldSize, flag_value);
+      FLAG_SET_CMDLINE(uintx, MaxNewSize, 170*M);
+      // Calculate what we expect the flag to be.
+      flag_value = MaxHeapSize - MaxNewSize;
+      verify_gen1_initial(flag_value);
 
   }
 
-  static void verify_min(size_t expected) {
+  static void verify_gen0_min(size_t expected) {
     MarkSweepPolicy msp;
     msp.initialize_all();
 
     assert(msp.min_gen0_size() <= expected, err_msg("%zu  > %zu", msp.min_gen0_size(), expected));
   }
 
-  static void verify_initial(size_t expected) {
+  static void verify_gen0_initial(size_t expected) {
     MarkSweepPolicy msp;
     msp.initialize_all();
 
     assert(msp.initial_gen0_size() == expected, err_msg("%zu != %zu", msp.initial_gen0_size(), expected));
   }
 
-  static void verify_scaled_initial(size_t initial_heap_size) {
+  static void verify_scaled_gen0_initial(size_t initial_heap_size) {
     MarkSweepPolicy msp;
     msp.initialize_all();
 
@@ -1053,6 +1076,21 @@
         err_msg("NewSize should have been set ergonomically to %zu, but was %zu", expected, NewSize));
   }
 
+  static void verify_gen1_min(size_t expected) {
+    MarkSweepPolicy msp;
+    msp.initialize_all();
+
+    assert(msp.min_gen1_size() <= expected, err_msg("%zu  > %zu", msp.min_gen1_size(), expected));
+  }
+
+  static void verify_gen1_initial(size_t expected) {
+    MarkSweepPolicy msp;
+    msp.initialize_all();
+
+    assert(msp.initial_gen1_size() == expected, err_msg("%zu != %zu", msp.initial_gen1_size(), expected));
+  }
+
+
 private:
   static size_t original_InitialHeapSize;
   static size_t original_MaxHeapSize;
@@ -1061,6 +1099,15 @@
   static size_t original_NewSize;
   static size_t original_OldSize;
 
+  static void set_basic_flag_values() {
+    FLAG_SET_ERGO(uintx, MaxHeapSize, 180 * M);
+    FLAG_SET_ERGO(uintx, InitialHeapSize, 100 * M);
+    FLAG_SET_ERGO(uintx, OldSize, 4 * M);
+    FLAG_SET_ERGO(uintx, NewSize, 1 * M);
+    FLAG_SET_ERGO(uintx, MaxNewSize, 80 * M);
+    Arguments::set_min_heap_size(40 * M);
+  }
+
   static void save_flags() {
     original_InitialHeapSize   = InitialHeapSize;
     original_MaxHeapSize       = MaxHeapSize;
@@ -1088,7 +1135,11 @@
 size_t TestGenCollectorPolicy::original_OldSize           = 0;
 
 void TestNewSize_test() {
-  TestGenCollectorPolicy::test();
+  TestGenCollectorPolicy::test_new_size();
+}
+
+void TestOldSize_test() {
+  TestGenCollectorPolicy::test_old_size();
 }
 
 #endif