diff --git a/src/hotspot/share/gc/shared/gcArguments.cpp b/src/hotspot/share/gc/shared/gcArguments.cpp index 424427c12b658..ec3d758c00a6c 100644 --- a/src/hotspot/share/gc/shared/gcArguments.cpp +++ b/src/hotspot/share/gc/shared/gcArguments.cpp @@ -25,10 +25,12 @@ #include "gc/shared/cardTable.hpp" #include "gc/shared/gcArguments.hpp" +#include "gc/shared/genArguments.hpp" #include "logging/log.hpp" #include "runtime/arguments.hpp" #include "runtime/globals.hpp" #include "runtime/globals_extension.hpp" +#include "runtime/os.hpp" #include "utilities/formatBuffer.hpp" #include "utilities/macros.hpp" @@ -56,6 +58,141 @@ void GCArguments::initialize() { } } +size_t GCArguments::limit_heap_by_allocatable_memory(size_t limit) { + // Limits the given heap size by the maximum amount of virtual + // memory this process is currently allowed to use. It also takes + // the virtual-to-physical ratio of the current GC into account. + size_t fraction = MaxVirtMemFraction * heap_virtual_to_physical_ratio(); + size_t max_allocatable = os::commit_memory_limit(); + + return MIN2(limit, max_allocatable / fraction); +} + +// Use static initialization to get the default before parsing +static const size_t DefaultHeapBaseMinAddress = HeapBaseMinAddress; + +static size_t clamp_by_size_t_max(uint64_t value) { + return (size_t)MIN2(value, (uint64_t)std::numeric_limits::max()); +} + +void GCArguments::set_heap_size() { + // Check if the user has configured any limit on the amount of RAM we may use. + bool has_ram_limit = !FLAG_IS_DEFAULT(MaxRAMPercentage) || + !FLAG_IS_DEFAULT(MinRAMPercentage) || + !FLAG_IS_DEFAULT(InitialRAMPercentage); + + const physical_memory_size_type avail_mem = os::physical_memory(); + + // If the maximum heap size has not been set with -Xmx, then set it as + // fraction of the size of physical memory, respecting the maximum and + // minimum sizes of the heap. + if (FLAG_IS_DEFAULT(MaxHeapSize)) { + uint64_t min_memory = (uint64_t)(((double)avail_mem * MinRAMPercentage) / 100); + uint64_t max_memory = (uint64_t)(((double)avail_mem * MaxRAMPercentage) / 100); + + const size_t reasonable_min = clamp_by_size_t_max(min_memory); + size_t reasonable_max = clamp_by_size_t_max(max_memory); + + if (reasonable_min < MaxHeapSize) { + // Small physical memory, so use a minimum fraction of it for the heap + reasonable_max = reasonable_min; + } else { + // Not-small physical memory, so require a heap at least + // as large as MaxHeapSize + reasonable_max = MAX2(reasonable_max, MaxHeapSize); + } + + if (!FLAG_IS_DEFAULT(ErgoHeapSizeLimit) && ErgoHeapSizeLimit != 0) { + // Limit the heap size to ErgoHeapSizeLimit + reasonable_max = MIN2(reasonable_max, ErgoHeapSizeLimit); + } + + reasonable_max = limit_heap_by_allocatable_memory(reasonable_max); + + if (!FLAG_IS_DEFAULT(InitialHeapSize)) { + // An initial heap size was specified on the command line, + // so be sure that the maximum size is consistent. Done + // after call to limit_heap_by_allocatable_memory because that + // method might reduce the allocation size. + reasonable_max = MAX2(reasonable_max, InitialHeapSize); + } else if (!FLAG_IS_DEFAULT(MinHeapSize)) { + reasonable_max = MAX2(reasonable_max, MinHeapSize); + } + +#ifdef _LP64 + if (UseCompressedOops) { + // HeapBaseMinAddress can be greater than default but not less than. + if (!FLAG_IS_DEFAULT(HeapBaseMinAddress)) { + if (HeapBaseMinAddress < DefaultHeapBaseMinAddress) { + // matches compressed oops printing flags + log_debug(gc, heap, coops)("HeapBaseMinAddress must be at least %zu " + "(%zuG) which is greater than value given %zu", + DefaultHeapBaseMinAddress, + DefaultHeapBaseMinAddress/G, + HeapBaseMinAddress); + FLAG_SET_ERGO(HeapBaseMinAddress, DefaultHeapBaseMinAddress); + } + } + + uintptr_t heap_end = HeapBaseMinAddress + MaxHeapSize; + uintptr_t max_coop_heap = Arguments::max_heap_for_compressed_oops(); + + // Limit the heap size to the maximum possible when using compressed oops + if (heap_end < max_coop_heap) { + // Heap should be above HeapBaseMinAddress to get zero based compressed + // oops but it should be not less than default MaxHeapSize. + max_coop_heap -= HeapBaseMinAddress; + } + + // If the user has configured any limit on the amount of RAM we may use, + // then disable compressed oops if the calculated max exceeds max_coop_heap + // and UseCompressedOops was not specified. + if (reasonable_max > max_coop_heap) { + if (FLAG_IS_ERGO(UseCompressedOops) && has_ram_limit) { + log_debug(gc, heap, coops)("UseCompressedOops disabled due to " + "max heap %zu > compressed oop heap %zu. " + "Please check the setting of MaxRAMPercentage %5.2f.", + reasonable_max, (size_t)max_coop_heap, MaxRAMPercentage); + FLAG_SET_ERGO(UseCompressedOops, false); + } else { + reasonable_max = max_coop_heap; + } + } + } +#endif // _LP64 + + log_trace(gc, heap)(" Maximum heap size %zu", reasonable_max); + FLAG_SET_ERGO(MaxHeapSize, reasonable_max); + } + + // If the minimum or initial heap_size have not been set or requested to be set + // ergonomically, set them accordingly. + if (InitialHeapSize == 0 || MinHeapSize == 0) { + size_t reasonable_minimum = clamp_by_size_t_max((uint64_t)OldSize + (uint64_t)NewSize); + reasonable_minimum = MIN2(reasonable_minimum, MaxHeapSize); + reasonable_minimum = limit_heap_by_allocatable_memory(reasonable_minimum); + + if (InitialHeapSize == 0) { + uint64_t initial_memory = (uint64_t)(((double)avail_mem * InitialRAMPercentage) / 100); + size_t reasonable_initial = clamp_by_size_t_max(initial_memory); + reasonable_initial = limit_heap_by_allocatable_memory(reasonable_initial); + + reasonable_initial = MAX3(reasonable_initial, reasonable_minimum, MinHeapSize); + reasonable_initial = MIN2(reasonable_initial, MaxHeapSize); + + FLAG_SET_ERGO(InitialHeapSize, (size_t)reasonable_initial); + log_trace(gc, heap)(" Initial heap size %zu", InitialHeapSize); + } + + // 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) { + FLAG_SET_ERGO(MinHeapSize, MIN2(reasonable_minimum, InitialHeapSize)); + log_trace(gc, heap)(" Minimum heap size %zu", MinHeapSize); + } + } +} + void GCArguments::initialize_heap_sizes() { initialize_alignments(); initialize_heap_flags_and_sizes(); diff --git a/src/hotspot/share/gc/shared/gcArguments.hpp b/src/hotspot/share/gc/shared/gcArguments.hpp index 7e9fffedaba31..6f44fc420aad8 100644 --- a/src/hotspot/share/gc/shared/gcArguments.hpp +++ b/src/hotspot/share/gc/shared/gcArguments.hpp @@ -40,10 +40,13 @@ class GCArguments { virtual void initialize_heap_flags_and_sizes(); virtual void initialize_size_info(); + size_t limit_heap_by_allocatable_memory(size_t size); + DEBUG_ONLY(void assert_flags();) DEBUG_ONLY(void assert_size_info();) public: + virtual void set_heap_size(); virtual void initialize(); // Return the (conservative) maximum heap alignment diff --git a/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp b/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp index 4d7ffce3a5dd4..096bee9e4a036 100644 --- a/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp +++ b/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp @@ -283,7 +283,7 @@ JVMFlag::Error SoftMaxHeapSizeConstraintFunc(size_t value, bool verbose) { } JVMFlag::Error HeapBaseMinAddressConstraintFunc(size_t value, bool verbose) { - // If an overflow happened in Arguments::set_heap_size(), MaxHeapSize will have too large a value. + // If an overflow happened in GCArguments::set_heap_size(), MaxHeapSize will have too large a value. // Check for this by ensuring that MaxHeapSize plus the requested min base address still fit within max_uintx. if (value > (max_uintx - MaxHeapSize)) { JVMFlag::printError(verbose, diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index d1304133d6314..bf60501de71c5 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -35,7 +35,6 @@ #include "gc/shared/gc_globals.hpp" #include "gc/shared/gcArguments.hpp" #include "gc/shared/gcConfig.hpp" -#include "gc/shared/genArguments.hpp" #include "gc/shared/stringdedup/stringDedup.hpp" #include "gc/shared/tlab_globals.hpp" #include "jvm.h" @@ -1489,138 +1488,6 @@ jint Arguments::set_ergonomics_flags() { return JNI_OK; } -size_t Arguments::limit_heap_by_allocatable_memory(size_t limit) { - size_t fraction = MaxVirtMemFraction * GCConfig::arguments()->heap_virtual_to_physical_ratio(); - size_t max_allocatable = os::commit_memory_limit(); - - return MIN2(limit, max_allocatable / fraction); -} - -// Use static initialization to get the default before parsing -static const size_t DefaultHeapBaseMinAddress = HeapBaseMinAddress; - -static size_t clamp_by_size_t_max(uint64_t value) { - return (size_t)MIN2(value, (uint64_t)std::numeric_limits::max()); -} - -void Arguments::set_heap_size() { - // Check if the user has configured any limit on the amount of RAM we may use. - bool has_ram_limit = !FLAG_IS_DEFAULT(MaxRAMPercentage) || - !FLAG_IS_DEFAULT(MinRAMPercentage) || - !FLAG_IS_DEFAULT(InitialRAMPercentage); - - const physical_memory_size_type avail_mem = os::physical_memory(); - - // If the maximum heap size has not been set with -Xmx, then set it as - // fraction of the size of physical memory, respecting the maximum and - // minimum sizes of the heap. - if (FLAG_IS_DEFAULT(MaxHeapSize)) { - uint64_t min_memory = (uint64_t)(((double)avail_mem * MinRAMPercentage) / 100); - uint64_t max_memory = (uint64_t)(((double)avail_mem * MaxRAMPercentage) / 100); - - const size_t reasonable_min = clamp_by_size_t_max(min_memory); - size_t reasonable_max = clamp_by_size_t_max(max_memory); - - if (reasonable_min < MaxHeapSize) { - // Small physical memory, so use a minimum fraction of it for the heap - reasonable_max = reasonable_min; - } else { - // Not-small physical memory, so require a heap at least - // as large as MaxHeapSize - reasonable_max = MAX2(reasonable_max, MaxHeapSize); - } - - if (!FLAG_IS_DEFAULT(ErgoHeapSizeLimit) && ErgoHeapSizeLimit != 0) { - // Limit the heap size to ErgoHeapSizeLimit - reasonable_max = MIN2(reasonable_max, ErgoHeapSizeLimit); - } - - reasonable_max = limit_heap_by_allocatable_memory(reasonable_max); - - if (!FLAG_IS_DEFAULT(InitialHeapSize)) { - // An initial heap size was specified on the command line, - // so be sure that the maximum size is consistent. Done - // after call to limit_heap_by_allocatable_memory because that - // method might reduce the allocation size. - reasonable_max = MAX2(reasonable_max, InitialHeapSize); - } else if (!FLAG_IS_DEFAULT(MinHeapSize)) { - reasonable_max = MAX2(reasonable_max, MinHeapSize); - } - -#ifdef _LP64 - if (UseCompressedOops) { - // HeapBaseMinAddress can be greater than default but not less than. - if (!FLAG_IS_DEFAULT(HeapBaseMinAddress)) { - if (HeapBaseMinAddress < DefaultHeapBaseMinAddress) { - // matches compressed oops printing flags - log_debug(gc, heap, coops)("HeapBaseMinAddress must be at least %zu " - "(%zuG) which is greater than value given %zu", - DefaultHeapBaseMinAddress, - DefaultHeapBaseMinAddress/G, - HeapBaseMinAddress); - FLAG_SET_ERGO(HeapBaseMinAddress, DefaultHeapBaseMinAddress); - } - } - - uintptr_t heap_end = HeapBaseMinAddress + MaxHeapSize; - uintptr_t max_coop_heap = max_heap_for_compressed_oops(); - - // Limit the heap size to the maximum possible when using compressed oops - if (heap_end < max_coop_heap) { - // Heap should be above HeapBaseMinAddress to get zero based compressed - // oops but it should be not less than default MaxHeapSize. - max_coop_heap -= HeapBaseMinAddress; - } - - // If the user has configured any limit on the amount of RAM we may use, - // then disable compressed oops if the calculated max exceeds max_coop_heap - // and UseCompressedOops was not specified. - if (reasonable_max > max_coop_heap) { - if (FLAG_IS_ERGO(UseCompressedOops) && has_ram_limit) { - log_debug(gc, heap, coops)("UseCompressedOops disabled due to " - "max heap %zu > compressed oop heap %zu. " - "Please check the setting of MaxRAMPercentage %5.2f.", - reasonable_max, (size_t)max_coop_heap, MaxRAMPercentage); - FLAG_SET_ERGO(UseCompressedOops, false); - } else { - reasonable_max = max_coop_heap; - } - } - } -#endif // _LP64 - - log_trace(gc, heap)(" Maximum heap size %zu", reasonable_max); - FLAG_SET_ERGO(MaxHeapSize, reasonable_max); - } - - // If the minimum or initial heap_size have not been set or requested to be set - // ergonomically, set them accordingly. - if (InitialHeapSize == 0 || MinHeapSize == 0) { - size_t reasonable_minimum = clamp_by_size_t_max((uint64_t)OldSize + (uint64_t)NewSize); - reasonable_minimum = MIN2(reasonable_minimum, MaxHeapSize); - reasonable_minimum = limit_heap_by_allocatable_memory(reasonable_minimum); - - if (InitialHeapSize == 0) { - uint64_t initial_memory = (uint64_t)(((double)avail_mem * InitialRAMPercentage) / 100); - size_t reasonable_initial = clamp_by_size_t_max(initial_memory); - reasonable_initial = limit_heap_by_allocatable_memory(reasonable_initial); - - reasonable_initial = MAX3(reasonable_initial, reasonable_minimum, MinHeapSize); - reasonable_initial = MIN2(reasonable_initial, MaxHeapSize); - - FLAG_SET_ERGO(InitialHeapSize, (size_t)reasonable_initial); - log_trace(gc, heap)(" Initial heap size %zu", InitialHeapSize); - } - - // 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) { - FLAG_SET_ERGO(MinHeapSize, MIN2(reasonable_minimum, InitialHeapSize)); - log_trace(gc, heap)(" Minimum heap size %zu", MinHeapSize); - } - } -} - // This must be called after ergonomics. void Arguments::set_bytecode_flags() { if (!RewriteBytecodes) { @@ -3685,7 +3552,7 @@ jint Arguments::apply_ergo() { if (result != JNI_OK) return result; // Set heap size based on available physical memory - set_heap_size(); + GCConfig::arguments()->set_heap_size(); GCConfig::arguments()->initialize(); diff --git a/src/hotspot/share/runtime/arguments.hpp b/src/hotspot/share/runtime/arguments.hpp index 2c31383f7a45f..0c5e3b6c441bd 100644 --- a/src/hotspot/share/runtime/arguments.hpp +++ b/src/hotspot/share/runtime/arguments.hpp @@ -273,12 +273,6 @@ class Arguments : AllStatic { static void set_use_compressed_oops(); static jint set_ergonomics_flags(); static void set_compact_headers_flags(); - // Limits the given heap size by the maximum amount of virtual - // memory this process is currently allowed to use. It also takes - // the virtual-to-physical ratio of the current GC into account. - static size_t limit_heap_by_allocatable_memory(size_t size); - // Setup heap size - static void set_heap_size(); // Bytecode rewriting static void set_bytecode_flags();