8223837: Add -XX:MinHeapSize flag to set the minimum heap size
authorstefank
Fri, 07 Jun 2019 13:50:14 +0200
changeset 55308 871bc449ce06
parent 55307 ed12027517c0
child 55309 8081b181bba8
8223837: Add -XX:MinHeapSize flag to set the minimum heap size Reviewed-by: pliden, tschatzl
src/hotspot/share/gc/shared/gcArguments.cpp
src/hotspot/share/gc/shared/gcArguments.hpp
src/hotspot/share/gc/shared/gc_globals.hpp
src/hotspot/share/gc/shared/genArguments.cpp
src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp
src/hotspot/share/gc/shared/jvmFlagConstraintsGC.hpp
src/hotspot/share/runtime/arguments.cpp
test/hotspot/jtreg/gc/arguments/TestMaxHeapSizeTools.java
--- a/src/hotspot/share/gc/shared/gcArguments.cpp	Thu Feb 14 14:54:05 2019 +0100
+++ b/src/hotspot/share/gc/shared/gcArguments.cpp	Fri Jun 07 13:50:14 2019 +0200
@@ -33,8 +33,6 @@
 #include "utilities/defaultStream.hpp"
 #include "utilities/macros.hpp"
 
-size_t MinHeapSize = 0;
-
 size_t HeapAlignment = 0;
 size_t SpaceAlignment = 0;
 
@@ -122,7 +120,7 @@
   assert(MaxHeapSize >= MinHeapSize, "Ergonomics decided on incompatible minimum and maximum heap sizes");
   assert(InitialHeapSize >= MinHeapSize, "Ergonomics decided on incompatible initial and minimum heap sizes");
   assert(MaxHeapSize >= InitialHeapSize, "Ergonomics decided on incompatible initial and maximum heap sizes");
-  assert(MaxHeapSize % HeapAlignment == 0, "MinHeapSize alignment");
+  assert(MinHeapSize % HeapAlignment == 0, "MinHeapSize alignment");
   assert(InitialHeapSize % HeapAlignment == 0, "InitialHeapSize alignment");
   assert(MaxHeapSize % HeapAlignment == 0, "MaxHeapSize alignment");
 }
@@ -149,7 +147,7 @@
     if (FLAG_IS_CMDLINE(InitialHeapSize) && InitialHeapSize > MaxHeapSize) {
       vm_exit_during_initialization("Initial heap size set to a larger value than the maximum heap size");
     }
-    if (MinHeapSize != 0 && MaxHeapSize < MinHeapSize) {
+    if (FLAG_IS_CMDLINE(MinHeapSize) && MaxHeapSize < MinHeapSize) {
       vm_exit_during_initialization("Incompatible minimum and maximum heap sizes specified");
     }
   }
@@ -166,28 +164,28 @@
   }
 
   // User inputs from -Xmx and -Xms must be aligned
-  MinHeapSize = align_up(MinHeapSize, HeapAlignment);
-  size_t aligned_initial_heap_size = align_up(InitialHeapSize, HeapAlignment);
-  size_t aligned_max_heap_size = align_up(MaxHeapSize, HeapAlignment);
-
   // Write back to flags if the values changed
-  if (aligned_initial_heap_size != InitialHeapSize) {
-    FLAG_SET_ERGO(InitialHeapSize, aligned_initial_heap_size);
+  if (!is_aligned(MinHeapSize, HeapAlignment)) {
+    FLAG_SET_ERGO(MinHeapSize, align_up(MinHeapSize, HeapAlignment));
   }
-  if (aligned_max_heap_size != MaxHeapSize) {
-    FLAG_SET_ERGO(MaxHeapSize, aligned_max_heap_size);
+  if (!is_aligned(InitialHeapSize, HeapAlignment)) {
+    FLAG_SET_ERGO(InitialHeapSize, align_up(InitialHeapSize, HeapAlignment));
+  }
+  if (!is_aligned(MaxHeapSize, HeapAlignment)) {
+    FLAG_SET_ERGO(MaxHeapSize, align_up(MaxHeapSize, HeapAlignment));
   }
 
-  if (FLAG_IS_CMDLINE(InitialHeapSize) && MinHeapSize != 0 &&
+  if (FLAG_IS_CMDLINE(InitialHeapSize) && FLAG_IS_CMDLINE(MinHeapSize) &&
       InitialHeapSize < MinHeapSize) {
     vm_exit_during_initialization("Incompatible minimum and initial heap sizes specified");
   }
+
   if (!FLAG_IS_DEFAULT(InitialHeapSize) && InitialHeapSize > MaxHeapSize) {
     FLAG_SET_ERGO(MaxHeapSize, InitialHeapSize);
   } else if (!FLAG_IS_DEFAULT(MaxHeapSize) && InitialHeapSize > MaxHeapSize) {
     FLAG_SET_ERGO(InitialHeapSize, MaxHeapSize);
     if (InitialHeapSize < MinHeapSize) {
-      MinHeapSize = InitialHeapSize;
+      FLAG_SET_ERGO(MinHeapSize, InitialHeapSize);
     }
   }
 
--- a/src/hotspot/share/gc/shared/gcArguments.hpp	Thu Feb 14 14:54:05 2019 +0100
+++ b/src/hotspot/share/gc/shared/gcArguments.hpp	Fri Jun 07 13:50:14 2019 +0200
@@ -30,8 +30,6 @@
 
 class CollectedHeap;
 
-extern size_t MinHeapSize;
-
 extern size_t HeapAlignment;
 extern size_t SpaceAlignment;
 
--- a/src/hotspot/share/gc/shared/gc_globals.hpp	Thu Feb 14 14:54:05 2019 +0100
+++ b/src/hotspot/share/gc/shared/gc_globals.hpp	Fri Jun 07 13:50:14 2019 +0200
@@ -713,6 +713,10 @@
           "to move")                                                        \
                                                                             \
   /* gc parameters */                                                       \
+  product(size_t, MinHeapSize, 0,                                           \
+          "Minimum heap size (in bytes); zero means use ergonomics")        \
+          constraint(MinHeapSizeConstraintFunc,AfterErgo)                   \
+                                                                            \
   product(size_t, InitialHeapSize, 0,                                       \
           "Initial heap size (in bytes); zero means use ergonomics")        \
           constraint(InitialHeapSizeConstraintFunc,AfterErgo)               \
--- a/src/hotspot/share/gc/shared/genArguments.cpp	Thu Feb 14 14:54:05 2019 +0100
+++ b/src/hotspot/share/gc/shared/genArguments.cpp	Fri Jun 07 13:50:14 2019 +0200
@@ -90,7 +90,7 @@
   }
   // If needed, synchronize MinHeapSize size and InitialHeapSize
   if (MinHeapSize < smallest_heap_size) {
-    MinHeapSize = smallest_heap_size;
+    FLAG_SET_ERGO(MinHeapSize, smallest_heap_size);
     if (InitialHeapSize < MinHeapSize) {
       FLAG_SET_ERGO(InitialHeapSize, smallest_heap_size);
     }
--- a/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp	Thu Feb 14 14:54:05 2019 +0100
+++ b/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp	Fri Jun 07 13:50:14 2019 +0200
@@ -319,6 +319,10 @@
   return MaxSizeForAlignment(name, value, heap_alignment, verbose);
 }
 
+JVMFlag::Error MinHeapSizeConstraintFunc(size_t value, bool verbose) {
+  return MaxSizeForHeapAlignment("MinHeapSize", value, verbose);
+}
+
 JVMFlag::Error InitialHeapSizeConstraintFunc(size_t value, bool verbose) {
   return MaxSizeForHeapAlignment("InitialHeapSize", value, verbose);
 }
--- a/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.hpp	Thu Feb 14 14:54:05 2019 +0100
+++ b/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.hpp	Fri Jun 07 13:50:14 2019 +0200
@@ -59,6 +59,7 @@
 JVMFlag::Error MaxGCPauseMillisConstraintFunc(uintx value, bool verbose);
 JVMFlag::Error GCPauseIntervalMillisConstraintFunc(uintx value, bool verbose);
 JVMFlag::Error InitialBootClassLoaderMetaspaceSizeConstraintFunc(size_t value, bool verbose);
+JVMFlag::Error MinHeapSizeConstraintFunc(size_t value, bool verbose);
 JVMFlag::Error InitialHeapSizeConstraintFunc(size_t value, bool verbose);
 JVMFlag::Error MaxHeapSizeConstraintFunc(size_t value, bool verbose);
 JVMFlag::Error SoftMaxHeapSizeConstraintFunc(size_t value, bool verbose);
--- a/src/hotspot/share/runtime/arguments.cpp	Thu Feb 14 14:54:05 2019 +0100
+++ b/src/hotspot/share/runtime/arguments.cpp	Fri Jun 07 13:50:14 2019 +0200
@@ -1630,8 +1630,8 @@
 #ifdef _LP64
   // MaxHeapSize is not set up properly at this point, but
   // the only value that can override MaxHeapSize if we are
-  // to use UseCompressedOops is InitialHeapSize.
-  size_t max_heap_size = MAX2(MaxHeapSize, InitialHeapSize);
+  // to use UseCompressedOops are InitialHeapSize and MinHeapSize.
+  size_t max_heap_size = MAX3(MaxHeapSize, InitialHeapSize, MinHeapSize);
 
   if (max_heap_size <= max_heap_for_compressed_oops()) {
 #if !defined(COMPILER1) || defined(TIERED)
@@ -1832,6 +1832,8 @@
       // after call to limit_by_allocatable_memory because that
       // method might reduce the allocation size.
       reasonable_max = MAX2(reasonable_max, (julong)InitialHeapSize);
+    } else if (!FLAG_IS_DEFAULT(MinHeapSize)) {
+      reasonable_max = MAX2(reasonable_max, (julong)MinHeapSize);
     }
 
     log_trace(gc, heap)("  Maximum heap size " SIZE_FORMAT, (size_t) reasonable_max);
@@ -1855,13 +1857,13 @@
 
       reasonable_initial = limit_by_allocatable_memory(reasonable_initial);
 
-      log_trace(gc, heap)("  Initial heap size " SIZE_FORMAT, (size_t)reasonable_initial);
       FLAG_SET_ERGO(InitialHeapSize, (size_t)reasonable_initial);
+      log_trace(gc, heap)("  Initial heap size " SIZE_FORMAT, InitialHeapSize);
     }
-    // If the minimum heap size has not been set (via -Xms),
+    // If the minimum heap size has not been set (via -Xms or -XX:MinHeapSize),
     // synchronize with InitialHeapSize to avoid errors with the default value.
     if (MinHeapSize == 0) {
-      MinHeapSize = MIN2((size_t)reasonable_minimum, InitialHeapSize);
+      FLAG_SET_ERGO(MinHeapSize, MIN2((size_t)reasonable_minimum, InitialHeapSize));
       log_trace(gc, heap)("  Minimum heap size " SIZE_FORMAT, MinHeapSize);
     }
   }
@@ -1903,8 +1905,9 @@
     if (FLAG_SET_CMDLINE(InitialHeapSize, initHeapSize) != JVMFlag::SUCCESS) {
       return JNI_EINVAL;
     }
-    // Currently the minimum size and the initial heap sizes are the same.
-    MinHeapSize = initHeapSize;
+    if (FLAG_SET_CMDLINE(MinHeapSize, initHeapSize) != JVMFlag::SUCCESS) {
+      return JNI_EINVAL;
+    }
   }
   if (FLAG_IS_DEFAULT(NewSize)) {
     // Make the young generation 3/8ths of the total heap.
@@ -2595,19 +2598,19 @@
       }
     // -Xms
     } else if (match_option(option, "-Xms", &tail)) {
-      julong long_initial_heap_size = 0;
+      julong size = 0;
       // an initial heap size of 0 means automatically determine
-      ArgsRange errcode = parse_memory_size(tail, &long_initial_heap_size, 0);
+      ArgsRange errcode = parse_memory_size(tail, &size, 0);
       if (errcode != arg_in_range) {
         jio_fprintf(defaultStream::error_stream(),
                     "Invalid initial heap size: %s\n", option->optionString);
         describe_range_error(errcode);
         return JNI_EINVAL;
       }
-      MinHeapSize = (size_t)long_initial_heap_size;
-      // Currently the minimum size and the initial heap sizes are the same.
-      // Can be overridden with -XX:InitialHeapSize.
-      if (FLAG_SET_CMDLINE(InitialHeapSize, (size_t)long_initial_heap_size) != JVMFlag::SUCCESS) {
+      if (FLAG_SET_CMDLINE(MinHeapSize, (size_t)size) != JVMFlag::SUCCESS) {
+        return JNI_EINVAL;
+      }
+      if (FLAG_SET_CMDLINE(InitialHeapSize, (size_t)size) != JVMFlag::SUCCESS) {
         return JNI_EINVAL;
       }
     // -Xmx
--- a/test/hotspot/jtreg/gc/arguments/TestMaxHeapSizeTools.java	Thu Feb 14 14:54:05 2019 +0100
+++ b/test/hotspot/jtreg/gc/arguments/TestMaxHeapSizeTools.java	Fri Jun 07 13:50:14 2019 +0200
@@ -55,6 +55,8 @@
     checkValidMinInitialHeapCombinations(gcflag);
     checkInvalidInitialMaxHeapCombinations(gcflag);
     checkValidInitialMaxHeapCombinations(gcflag);
+    checkInvalidMinMaxHeapCombinations(gcflag);
+    checkValidMinMaxHeapCombinations(gcflag);
   }
 
   public static void checkMinInitialErgonomics(String gcflag) throws Exception {
@@ -71,18 +73,33 @@
 
     // -Xms is not set
     checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize }, values, -1, -1);
+    checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-XX:MinHeapSize=" + smallValue }, values, smallValue, -1);
+    checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-XX:MinHeapSize=" + largeValue }, values, largeValue, -1);
+    checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-XX:MinHeapSize=0" }, values, -1, -1);
     checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-XX:InitialHeapSize=" + smallValue }, values, -1, smallValue);
     checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-XX:InitialHeapSize=" + largeValue }, values, -1, largeValue);
     checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-XX:InitialHeapSize=0" }, values, -1, -1);
+    // Some extra checks when both are set.
+    checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-XX:MinHeapSize=" + smallValue, "-XX:InitialHeapSize=" + smallValue }, values, smallValue, smallValue);
+    checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-XX:MinHeapSize=" + smallValue, "-XX:InitialHeapSize=" + largeValue }, values, smallValue, largeValue);
+    checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-XX:MinHeapSize=" + largeValue, "-XX:InitialHeapSize=" + largeValue }, values, largeValue, largeValue);
 
     // -Xms is set to zero
     checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms0" }, values, -1, -1);
+    checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms0", "-XX:MinHeapSize=" + smallValue }, values, smallValue, -1);
+    checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms0", "-XX:MinHeapSize=" + largeValue }, values, largeValue, -1);
+    checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms0", "-XX:MinHeapSize=0" }, values, -1, -1);
     checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms0", "-XX:InitialHeapSize=" + smallValue }, values, -1, smallValue);
     checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms0", "-XX:InitialHeapSize=" + largeValue }, values, -1, largeValue);
     checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms0", "-XX:InitialHeapSize=0" }, values, -1, -1);
+    checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms0", "-XX:MinHeapSize=" + smallValue, "-XX:InitialHeapSize=" + smallValue }, values, smallValue, smallValue);
+    checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms0", "-XX:MinHeapSize=" + smallValue, "-XX:InitialHeapSize=" + largeValue }, values, smallValue, largeValue);
+    checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms0", "-XX:MinHeapSize=" + largeValue, "-XX:InitialHeapSize=" + largeValue }, values, largeValue, largeValue);
 
     // -Xms is set to small value
     checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms" + smallValue }, values, -1, -1);
+    checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms" + smallValue, "-XX:MinHeapSize=" + smallValue }, values, smallValue, smallValue);
+    checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms" + smallValue, "-XX:MinHeapSize=0" }, values, -1, smallValue);
     checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms" + smallValue, "-XX:InitialHeapSize=" + smallValue }, values, smallValue, smallValue);
     checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms" + smallValue, "-XX:InitialHeapSize=" + largeValue }, values, smallValue, largeValue);
     checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms" + smallValue, "-XX:InitialHeapSize=0" }, values, smallValue, -1);
@@ -90,6 +107,7 @@
     // -Xms is set to large value
     checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms" + largeValue }, values, largeValue, largeValue);
     checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms" + largeValue, "-XX:InitialHeapSize=0" }, values, largeValue, -1);
+    checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms" + largeValue, "-XX:MinHeapSize=0" }, values, -1, largeValue);
   }
 
   private static long align_up(long value, long alignment) {
@@ -116,6 +134,9 @@
   private static void checkInvalidMinInitialHeapCombinations(String gcflag) throws Exception {
     expectError(new String[] { gcflag, "-XX:InitialHeapSize=1023K", "-version" });
     expectError(new String[] { gcflag, "-Xms64M", "-XX:InitialHeapSize=32M", "-version" });
+    expectError(new String[] { gcflag, "-XX:MinHeapSize=1023K", "-version" });
+    expectError(new String[] { gcflag, "-Xms4M", "-XX:MinHeapSize=8M", "-version" });
+    expectError(new String[] { gcflag, "-XX:MinHeapSize=8M -XX:InitialHeapSize=4m" });
   }
 
   private static void checkValidMinInitialHeapCombinations(String gcflag) throws Exception {
@@ -123,8 +144,13 @@
     expectValid(new String[] { gcflag, "-XX:InitialHeapSize=8M", "-Xms4M", "-version" });
     expectValid(new String[] { gcflag, "-Xms4M", "-XX:InitialHeapSize=8M", "-version" });
     expectValid(new String[] { gcflag, "-XX:InitialHeapSize=8M", "-Xms8M", "-version" });
+    expectValid(new String[] { gcflag, "-XX:MinHeapSize=1024K", "-version" });
+    expectValid(new String[] { gcflag, "-XX:MinHeapSize=8M", "-Xms4M", "-version" });
+    expectValid(new String[] { gcflag, "-XX:MinHeapSize=8M", "-Xms8M", "-version" });
+    expectValid(new String[] { gcflag, "-Xms8M", "-XX:MinHeapSize=4M", "-version" });
     // the following is not an error as -Xms sets both minimal and initial heap size
     expectValid(new String[] { gcflag, "-XX:InitialHeapSize=4M", "-Xms8M", "-version" });
+    expectValid(new String[] { gcflag, "-XX:MinHeapSize=4M", "-Xms8M", "-version" });
   }
 
   private static void checkInvalidInitialMaxHeapCombinations(String gcflag) throws Exception {
@@ -133,6 +159,12 @@
     expectError(new String[] { gcflag, "-XX:InitialHeapSize=8M", "-XX:MaxHeapSize=4M", "-version" });
   }
 
+  private static void checkInvalidMinMaxHeapCombinations(String gcflag) throws Exception {
+    expectError(new String[] { gcflag, "-XX:MaxHeapSize=4M", "-XX:MinHeapSize=8M", "-version" });
+    expectError(new String[] { gcflag, "-XX:MinHeapSize=8M", "-XX:MaxHeapSize=4M", "-version" });
+  }
+
+
   private static void checkValidInitialMaxHeapCombinations(String gcflag) throws Exception {
     expectValid(new String[] { gcflag, "-XX:InitialHeapSize=4M", "-XX:MaxHeapSize=8M", "-version" });
     expectValid(new String[] { gcflag, "-XX:MaxHeapSize=8M", "-XX:InitialHeapSize=4M", "-version" });
@@ -141,6 +173,14 @@
     expectValid(new String[] { gcflag, "-XX:MaxHeapSize=4M", "-XX:InitialHeapSize=0M", "-version" });
   }
 
+  private static void checkValidMinMaxHeapCombinations(String gcflag) throws Exception {
+    expectValid(new String[] { gcflag, "-XX:MinHeapSize=4M", "-XX:MaxHeapSize=8M", "-version" });
+    expectValid(new String[] { gcflag, "-XX:MaxHeapSize=8M", "-XX:MinHeapSize=4M", "-version" });
+    expectValid(new String[] { gcflag, "-XX:MaxHeapSize=4M", "-XX:MinHeapSize=4M", "-version" });
+    // a value of "0" for min heap size means auto-detect
+    expectValid(new String[] { gcflag, "-XX:MaxHeapSize=4M", "-XX:MinHeapSize=0M", "-version" });
+  }
+
   private static long valueAfter(String source, String match) {
     int start = source.indexOf(match) + match.length();
     String tail = source.substring(start).split(" ")[0];
@@ -294,4 +334,3 @@
     expect(flags, false, false, 0);
   }
 }
-