[JAVA] Default values for MaxHeapSize and InitialHeapSize

Introduction

The default values for MaxHeapSize (-Xmx) and InitialHeapSize are a bit written in the official documentation, but not detailed. So I looked it up with the sauce.

The target version is OpenJDK 11 The actual machine confirmation environment is CentOS7

Conclusion

MaxHeapSize MaxHeapSize is determined as follows.

Memory size(※1) value
About 248M or less(※2) Memory size* 0.5 (※4)
Approximately 248M to 496M or less MaxHeapSize(124MB)
Approximately 496M to 120G or less(※3) Memory size* 0.25 (※5)
About 120G or more About 30G(※6)

More details.

(※1) If MaxRAM is specified, its value, otherwise the actual memory size. From now on, memory size is used in this sense.

(※2) 248M is from the following. MaxHeapSize / (MinRAMPercentage/100) = 124M / (50/100) = 248M

(※4) 0.5 is the value of MinRAM Percentage, strictly speaking: Memory size * (MinRAMPercentage / 100)

(※5) 0.25 is the MaxRAM Percentage value, strictly speaking: Memory size * (MaxRAMPercentage / 100)

(※6) 30GB is from the following. 32GB - HeapBaseMinAddress (=2GB) 32GB is the maximum Java heap offset when using Compressed Oops. Details are explained in the source.

InitialHeapSize The default value of InitialHeapSize is determined as follows. Whichever of the following is larger (however, it does not exceed MaxHeapSize)

--Memory size * InitialRAMPercentage

Source

Initial default value for MaxHeapSize

The first default value for MaxHeapSize is defined below. Src / hotspot is omitted in the following source path.

share/gc/shared/gc_globals.hpp



  product(size_t, MaxHeapSize, ScaleForWordSize(96*M),                      \
          "Maximum heap size (in bytes)")                                   \
          constraint(MaxHeapSizeConstraintFunc,AfterErgo)                   \

ScaleForWordSize is defined below.

share/runtime/globals.hpp


#ifdef _LP64
#define ScaleForWordSize(x) align_down_((x) * 13 / 10, HeapWordSize)
#else
#define ScaleForWordSize(x) (x)
#endif

Therefore, MaxHeapSize is 96 * 1.3 = 124.8MB 1.3 seems to take into account the fact that the pointer size is doubled compared to 32bit.

set_heap_size()

MaxHeapSize The default value for InitialHeapSize is mostly determined by set_heap_size () in arguments.cpp.

share/runtime/arguments.cpp


void Arguments::set_heap_size() {
  julong phys_mem =
    FLAG_IS_DEFAULT(MaxRAM) ? MIN2(os::physical_memory(), (julong)MaxRAM)
                            : (julong)MaxRAM;

If MaxRAM is specified, MaxRAM Unless otherwise specified, MaxRAM (default 1G) or the smaller of physical memory is set to phys_mem.

set_heap_size()


  // Convert deprecated flags
  if (FLAG_IS_DEFAULT(MaxRAMPercentage) &&
      !FLAG_IS_DEFAULT(MaxRAMFraction))
    MaxRAMPercentage = 100.0 / MaxRAMFraction;

  if (FLAG_IS_DEFAULT(MinRAMPercentage) &&
      !FLAG_IS_DEFAULT(MinRAMFraction))
    MinRAMPercentage = 100.0 / MinRAMFraction;

  if (FLAG_IS_DEFAULT(InitialRAMPercentage) &&
      !FLAG_IS_DEFAULT(InitialRAMFraction))
    InitialRAMPercentage = 100.0 / InitialRAMFraction;

MaxRAMFraction MinRAMFraction InitialRAMFraction is now deprecated and replaced by MaxRAMPercentage MinRAMPercentage InitialRAMFraction. If specified in the old option, convert to the new option here. In the past, it was specified as a fraction of memory, but in Java 11, it is specified as a percentage of memory.

set_heap_size()


  // 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)) {
    julong reasonable_max = (julong)((phys_mem * MaxRAMPercentage) / 100);
    const julong reasonable_min = (julong)((phys_mem * MinRAMPercentage) / 100);
    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, (julong)MaxHeapSize);
    }

When MaxHeapSize is not specified and the memory is 248M (MaxHeapSize / (MinRAMPercentage / 100)) or less reasonable_max = memory * 0.5 Otherwise reasonable_max = memory * 0.25 or 126M larger Will be. reasonable_max is the value that will be set later (where ★) as MaxHeapSize.

set_heap_size()


    if (!FLAG_IS_DEFAULT(ErgoHeapSizeLimit) && ErgoHeapSizeLimit != 0) {
      // Limit the heap size to ErgoHeapSizeLimit
      reasonable_max = MIN2(reasonable_max, (julong)ErgoHeapSizeLimit);
    }

ErgoHeapSizeLimit defaults to 0 If ErgoHeapSizeLimit is specified and is less than reasonable_max, set reasonable_max to ErgoHeapSizeLimit. The use of ErgoHeapSizeLimit is unknown. Only used here.

set_heap_size()


    if (UseCompressedOops) {
      // Limit the heap size to the maximum possible when using compressed oops
      julong max_coop_heap = (julong)max_heap_for_compressed_oops();  // 32GB

      // HeapBaseMinAddress can be greater than default but not less than.
      if (!FLAG_IS_DEFAULT(HeapBaseMinAddress)) {  // HeapBaseMinAddress = 2GB
        if (HeapBaseMinAddress < DefaultHeapBaseMinAddress) {
          // matches compressed oops printing flags
          log_debug(gc, heap, coops)("HeapBaseMinAddress must be at least " SIZE_FORMAT
                                     " (" SIZE_FORMAT "G) which is greater than value given " SIZE_FORMAT,
                                     DefaultHeapBaseMinAddress,
                                     DefaultHeapBaseMinAddress/G,
                                     HeapBaseMinAddress);
          FLAG_SET_ERGO(size_t, HeapBaseMinAddress, DefaultHeapBaseMinAddress);
        }
      }

      if (HeapBaseMinAddress + MaxHeapSize < max_coop_heap) { // 2G + 124M < 32G
        // Heap should be above HeapBaseMinAddress to get zero based compressed oops
        // but it should be not less than default MaxHeapSize.
        max_coop_heap -= HeapBaseMinAddress;  //About 30GB
      }
      reasonable_max = MIN2(reasonable_max, max_coop_heap);
    }

CompressedOop processing. UseCompressedOops is true by default on 64bit OS. max_heap_for_compressed_oops () returns the maximum Java heap offset (= 32GB) in CompressedOop. (Details will be described later) If HeapBaseMinAddress is specified to be smaller than the default value of 2GB, it is corrected to 2GB. If HeapBaseMinAddress + MaxHeapSize is less than 32GB (true by default) Set reasonable_max to 32GB --HeapBaseMinAddress (= 30GB). This is because the Java heap size needs to be reduced by the Java heap start address (HeapBaseMinAddress).

set_heap_size()


    reasonable_max = limit_by_allocatable_memory(reasonable_max);

Check if allocateable is possible with the size of reasonable_max determined in the previous process, and if not, set the possible size.

set_heap_size()


    if (!FLAG_IS_DEFAULT(InitialHeapSize)) {  //InitialHeapSize Default 0
      // An initial heap size was specified on the command line,
      // so be sure that the maximum size is consistent.  Done
      // after call to limit_by_allocatable_memory because that
      // method might reduce the allocation size.
      reasonable_max = MAX2(reasonable_max, (julong)InitialHeapSize);
    }

If InitialHeapSize is set, reasonable_max is set to the larger value of reasonable_max and InitialHeapSize. It is inconsistent that MaxHeapSize is smaller than InitialHeapSize.

set_heap_size()


    log_trace(gc, heap)("  Maximum heap size " SIZE_FORMAT, (size_t) reasonable_max);
    FLAG_SET_ERGO(size_t, MaxHeapSize, (size_t)reasonable_max);
  }

Set reasonable_max determined in the previous process as MaxHeapSize. (★)

set_heap_size()


  // If the minimum or initial heap_size have not been set or requested to be set
  // ergonomically, set them accordingly.

  if (InitialHeapSize == 0 || min_heap_size() == 0) {
    julong reasonable_minimum = (julong)(OldSize + NewSize);

    reasonable_minimum = MIN2(reasonable_minimum, (julong)MaxHeapSize);

    reasonable_minimum = limit_by_allocatable_memory(reasonable_minimum);

    if (InitialHeapSize == 0) {
      julong reasonable_initial = (julong)((phys_mem * InitialRAMPercentage) / 100);

      reasonable_initial = MAX3(reasonable_initial, reasonable_minimum, (julong)min_heap_size());
      reasonable_initial = MIN2(reasonable_initial, (julong)MaxHeapSize);

      reasonable_initial = limit_by_allocatable_memory(reasonable_initial);

      log_trace(gc, heap)("  Initial heap size " SIZE_FORMAT, (size_t)reasonable_initial);
      FLAG_SET_ERGO(size_t, InitialHeapSize, (size_t)reasonable_initial);
    }
    ....

If InitialHeapSize is not set, InitialHeapSize will be -(Memory size * InitialRAMPercentage) Or

max_heap_for_compressed_oops()

max_heap_for_compressed_oops returns the maximum Java heap offset of 32GB in Compressed Oop.

python


size_t Arguments::max_heap_for_compressed_oops() {
  // Avoid sign flip.
  assert(OopEncodingHeapMax > (uint64_t)os::vm_page_size(), "Unusual page size");
  // We need to fit both the NULL page and the heap into the memory budget, while
  // keeping alignment constraints of the heap. To guarantee the latter, as the
  // NULL page is located before the heap, we pad the NULL page to the conservative
  // maximum alignment that the GC may ever impose upon the heap.

  size_t displacement_due_to_null_page = align_up((size_t)os::vm_page_size(),
                                                  _conservative_max_heap_alignment);

  LP64_ONLY(return OopEncodingHeapMax - displacement_due_to_null_page);
  NOT_LP64(ShouldNotReachHere(); return 0);
}

displacement_due_to_null_page is 4K. OopEncodingHeapMax is set below.

python


void set_object_alignment() {
  ....

  LogMinObjAlignmentInBytes  = exact_log2(ObjectAlignmentInBytes);
  LogMinObjAlignment         = LogMinObjAlignmentInBytes - LogHeapWordSize;

  // Oop encoding heap max
  OopEncodingHeapMax = (uint64_t(max_juint) + 1) << LogMinObjAlignmentInBytes;

LogMinObjAlignmentInBytes is 8 as follows.

share/runtime/globals.hpp


  lp64_product(intx, ObjectAlignmentInBytes, 8,                             \
          "Default object alignment in bytes, 8 is minimum")                \

So LogMinObjAlignmentInBytes is 3 in log2 (8) OopEncodingHeapMax is 0x1 0000 0000 = 4GB << 3 and 32GB

HeapBaseMinAddress is 2GB

os_cpu/linux_x86/globals_linux_x86.hpp


// Used on 64 bit platforms for UseCompressedOops base address
define_pd_global(size_t, HeapBaseMinAddress,     2*G);

Therefore max_coop_heap = 32GB --2GB = about 30GB (actually it is a little different because there is alignment)

Actual machine confirmation

I confirmed the above contents using PrintFlagsInitial or PrintFlagsFinal on the actual machine. The output results are omitted as appropriate. MaxRAM is used as the memory size.

MaxHeapSize Initial default value for MaxHeapSize (using PrintFlagsInitial) centos7 >> java -XX:+PrintFlagsInitial -version | grep MaxHeapSize size_t MaxHeapSize = 130862280

When the memory size is 1024m, it is 256m, which is 1/4 of that. centos7 >> java -XX:MaxRAM=1024m -XX:+PrintFlagsFinal -version | grep MaxHeapSize size_t MaxHeapSize = 268435456

When the memory size is 248m, it is half that, 124m. centos7 >> java -XX:MaxRAM=248m -XX:+PrintFlagsFinal -version | grep MaxHeapSize size_t MaxHeapSize = 130023424

When the memory size is 120G, it is about 30G (29.97G). centos7 >> java -XX:MaxRAM=120G -XX:+PrintFlagsFinal -version | grep MaxHeapSize size_t MaxHeapSize = 32178700288

When MaxRAMPercentage is 10, it is 10% of the memory size 10G. centos7 >> java -XX:MaxRAM=10G -XX:MaxRAMPercentage=10 -XX:+PrintFlagsFinal -version | grep MaxHeapSize size_t MaxHeapSize = 1073741824

InitialHeapSize InitialHeapSize is 1M, which is 1/64 of the memory size by default. centos7 >> java -XX:MaxRAM=640M -XX:+PrintFlagsFinal -version | grep InitialHeapSize size_t InitialHeapSize = 10485760

When InitialRAMPercentage is 5, it is 5% of the memory size 10G. centos7 >> java -XX:MaxRAM=10G -XX:InitialRAMPercentage=5 -XX:+PrintFlagsFinal -version | grep InitialHeapSize size_t InitialHeapSize = 536870912

If the sum of OldSize and NewSize is larger than the default value of InitialHeapSize, the value is 40M. centos7 >> java -XX:MaxRAM=640M -XX:OldSize=20m -XX:NewSize=20m -XX:+PrintFlagsFinal -version | grep InitialHeapSize size_t InitialHeapSize = 41943040

Recommended Posts

Default values for MaxHeapSize and InitialHeapSize
[Ruby] Arguments with keywords and default values of arguments
[Ruby] Setting values ​​and memorandum for the table
Default value for server.servlet.session.timeout
Difficult to handle minimum values for Java8 LocalDateTime and Java6 Date
About for statement and if statement
default value for android: exported
Scheduler for RxAndroid and RxSwing
Java while and for statements