Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 137 additions & 0 deletions src/hotspot/share/gc/shared/gcArguments.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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<size_t>::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();
Expand Down
3 changes: 3 additions & 0 deletions src/hotspot/share/gc/shared/gcArguments.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
135 changes: 1 addition & 134 deletions src/hotspot/share/runtime/arguments.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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<size_t>::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) {
Expand Down Expand Up @@ -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();

Expand Down
6 changes: 0 additions & 6 deletions src/hotspot/share/runtime/arguments.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down