[JAVA] Valeurs par défaut pour MaxHeapSize et InitialHeapSize

introduction

Les valeurs par défaut pour MaxHeapSize (-Xmx) et InitialHeapSize sont un peu écrites dans la documentation officielle, mais pas détaillées. Alors je l'ai recherché avec la source.

La version cible est OpenJDK 11 L'environnement réel de confirmation de la machine est CentOS7

Conclusion

MaxHeapSize MaxHeapSize est déterminé comme suit.

Taille mémoire(※1) valeur
Environ 248 M ou moins(※2) Taille mémoire* 0.5 (※4)
Environ 248 M à 496 M ou moins MaxHeapSize(124MB)
Environ 496M à 120G ou moins(※3) Taille mémoire* 0.25 (※5)
Environ 120G ou plus Environ 30G(※6)

Plus de détails.

(※1) Si MaxRAM est spécifié, sa valeur, sinon la taille réelle de la mémoire. Désormais, la taille de la mémoire est utilisée dans ce sens.

(※2) 248M est de ce qui suit. MaxHeapSize / (MinRAMPercentage/100) = 124M / (50/100) = 248M

(※4) 0.5 est la valeur du pourcentage MinRAM, à proprement parler: Taille de la mémoire * (MinRAMPercentage / 100)

(※5) 0,25 est la valeur du pourcentage MaxRAM, à proprement parler: Taille de la mémoire * (MaxRAMPercentage / 100)

(※6) 30 Go est de ce qui suit. 32GB - HeapBaseMinAddress (=2GB) 32 Go est le décalage maximum du tas Java lors de l'utilisation de Compressed Oops. Les détails sont expliqués dans la source.

InitialHeapSize La valeur par défaut de InitialHeapSize est déterminée comme suit. Quel que soit le plus grand des éléments suivants (cependant, il ne dépasse pas MaxHeapSize)

--Taille de la mémoire * InitialRAMPercentage

La source

Valeur par défaut initiale pour MaxHeapSize

La première valeur par défaut de MaxHeapSize est définie ci-dessous. Src / hotspot est omis dans le chemin source suivant.

share/gc/shared/gc_globals.hpp



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

ScaleForWordSize est défini ci-dessous.

share/runtime/globals.hpp


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

Par conséquent, MaxHeapSize est 96 * 1,3 = 124,8 Mo 1.3 semble prendre en compte le fait que la taille du pointeur est doublée par rapport à 32 bits.

set_heap_size()

MaxHeapSize La valeur par défaut de InitialHeapSize est principalement déterminée par set_heap_size () dans 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;

Si MaxRAM est spécifié, MaxRAM Sauf indication contraire, MaxRAM (par défaut 1G) ou la plus petite de la mémoire physique est définie sur 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 est désormais obsolète et remplacé par MaxRAMPercentage MinRAMPercentage InitialRAMFraction. Si spécifié dans l'ancienne option, convertissez-le ici en nouvelle option. Dans le passé, il était spécifié comme une fraction de la mémoire, mais dans Java 11, il était spécifié comme un pourcentage de la mémoire.

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);
    }

Lorsque MaxHeapSize n'est pas spécifié et que la mémoire est de 248 Mo (MaxHeapSize / (MinRAMPercentage / 100)) ou moins raisonnable_max = mémoire * 0,5 Autrement raisonnable_max = mémoire * 0,25 ou 126M plus grande Sera. raisonnable_max est la valeur qui sera définie plus tard (où ★) comme 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 prend la valeur par défaut 0 Si ErgoHeapSizeLimit est spécifié et est inférieur à raisonnable_max, définissez raisonnable_max sur ErgoHeapSizeLimit. L'utilisation d'ErgoHeapSizeLimit est inconnue. Utilisé uniquement ici.

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;  //Environ 30 Go
      }
      reasonable_max = MIN2(reasonable_max, max_coop_heap);
    }

Traitement CompressedOop. UseCompressedOops est true par défaut sur les systèmes d'exploitation 64 bits. max_heap_for_compressed_oops () renvoie le décalage maximum du tas Java (= 32 Go) dans CompressedOop. (Les détails seront décrits plus tard) Si HeapBaseMinAddress est spécifié pour être inférieur à la valeur par défaut de 2 Go, il sera corrigé à 2 Go. Si HeapBaseMinAddress + MaxHeapSize est inférieur à 32 Go (vrai par défaut) Définissez raisonnable_max sur 32 Go --HeapBaseMinAddress (= 30 Go). En effet, la taille du tas Java doit être réduite par l'adresse de début du tas Java (HeapBaseMinAddress).

set_heap_size()


    reasonable_max = limit_by_allocatable_memory(reasonable_max);

Vérifiez si allouable est possible avec la taille de raisonnable_max déterminée dans le traitement jusqu'à présent, et sinon, définissez la taille possible.

set_heap_size()


    if (!FLAG_IS_DEFAULT(InitialHeapSize)) {  //InitialHeapSize par défaut 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);
    }

Si InitialHeapSize est défini, raisonnable_max est défini sur la valeur la plus élevée de raisonnable_max et InitialHeapSize. Il est incohérent que MaxHeapSize soit plus petit que 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);
  }

Définissez raisonnable_max déterminé dans le processus précédent comme 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);
    }
    ....

Si InitialHeapSize n'est pas défini, InitialHeapSize sera

max_heap_for_compressed_oops()

max_heap_for_compressed_oops renvoie 32 Go, qui est le décalage maximum du tas Java dans 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);
}

déplacement_due_to_null_page est 4K. OopEncodingHeapMax est défini ci-dessous.

python


void set_object_alignment() {
  ....

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

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

LogMinObjAlignmentInBytes vaut 8 comme suit.

share/runtime/globals.hpp


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

Donc LogMinObjAlignmentInBytes vaut 3 dans log2 (8) OopEncodingHeapMax est 0x1 0000 0000 = 4 Go << 3 et 32 Go

HeapBaseMinAddress est de 2 Go

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);

Par conséquent max_coop_heap = 32 Go - 2 Go = environ 30 Go (en fait, c'est un peu différent car il y a alignement, etc.)

Confirmation réelle de la machine

J'ai confirmé le contenu ci-dessus en utilisant PrintFlagsInitial ou PrintFlagsFinal sur la machine réelle. Le résultat de sortie est omis le cas échéant. MaxRAM est utilisé comme taille de mémoire.

MaxHeapSize Valeur par défaut initiale pour MaxHeapSize (à l'aide de PrintFlagsInitial) centos7 >> java -XX:+PrintFlagsInitial -version | grep MaxHeapSize size_t MaxHeapSize = 130862280

Lorsque la taille de la mémoire est de 1024 m, elle est de 256 m, soit 1/4 de cela. centos7 >> java -XX:MaxRAM=1024m -XX:+PrintFlagsFinal -version | grep MaxHeapSize size_t MaxHeapSize = 268435456

Lorsque la taille de la mémoire est de 248 m, elle est de moitié, 124 m. centos7 >> java -XX:MaxRAM=248m -XX:+PrintFlagsFinal -version | grep MaxHeapSize size_t MaxHeapSize = 130023424

Lorsque la taille de la mémoire est de 120G, elle est d'environ 30G (29,97G). centos7 >> java -XX:MaxRAM=120G -XX:+PrintFlagsFinal -version | grep MaxHeapSize size_t MaxHeapSize = 32178700288

Lorsque MaxRAMPercentage est égal à 10, il correspond à 10% de la taille de la mémoire 10G. centos7 >> java -XX:MaxRAM=10G -XX:MaxRAMPercentage=10 -XX:+PrintFlagsFinal -version | grep MaxHeapSize size_t MaxHeapSize = 1073741824

InitialHeapSize InitialHeapSize est 1M, soit 1/64 de la taille de la mémoire, par défaut. centos7 >> java -XX:MaxRAM=640M -XX:+PrintFlagsFinal -version | grep InitialHeapSize size_t InitialHeapSize = 10485760

Lorsque InitialRAMPercentage est égal à 5, il correspond à 5% de la taille de la mémoire 10G. centos7 >> java -XX:MaxRAM=10G -XX:InitialRAMPercentage=5 -XX:+PrintFlagsFinal -version | grep InitialHeapSize size_t InitialHeapSize = 536870912

Si la somme d'OldSize et de NewSize est supérieure à la valeur par défaut de InitialHeapSize, la valeur sera 40M. centos7 >> java -XX:MaxRAM=640M -XX:OldSize=20m -XX:NewSize=20m -XX:+PrintFlagsFinal -version | grep InitialHeapSize size_t InitialHeapSize = 41943040

Recommended Posts

Valeurs par défaut pour MaxHeapSize et InitialHeapSize
[Ruby] Mots clés avec mots clés et valeurs par défaut des arguments
Valeur par défaut pour server.servlet.session.timeout
Difficile de gérer les valeurs minimales avec Java8 LocalDateTime et Java6 Date
À propos de l'instruction et de l'instruction if
valeur par défaut d'Android: exporté
RxAndroid et RxSwing Scheduler
Instructions Java while et for