When the Java GC method (Parallel GC, G1GC, etc.) is not specified by the option, I tried to follow the process in the Java VM source code to see how it is determined. The source is from OpenJDK Java11. Src / hotspot is omitted in the following source path.
To write the conclusion first, if the GC method is not specified by the option, it will be as follows.
| conditions | GC method | 
|---|---|
| Server class machine | UseG1GC | 
| Client class machine | UseSerialGC | 
A server class machine is basically a machine with 2 or more CPUs and 2G or more of memory.
It is called in the following order when JavaVM is started.
Threads::create_vm (share/runtime/thread.cpp)
  Arguments::apply_ergo (share/runtime/arguments.cpp)
    Arguments::set_ergonomics_flags
      GCConfig::initialize (share/gc/shared/gcConfig.cpp)
        select_gc
          select_gc_ergonomically
Follow each source in turn.
share/runtime/thread.cpp
jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
  ....
  // Parse arguments
  // Note: this internally calls os::init_container_support()
  jint parse_result = Arguments::parse(args);
  if (parse_result != JNI_OK) return parse_result;
  os::init_before_ergo();
  jint ergo_result = Arguments::apply_ergo();   // ★
  if (ergo_result != JNI_OK) return ergo_result;
  ...
If java arguments are parsed with Arguments :: parse and the GC method is specified, the option will be true. For example, -XX: + UseParallelGC will set UseParallelGC to true. Basically, the value of each option in the JVM uses a variable with the name of the option on the source.
share/runtime/arguments.cpp
jint Arguments::apply_ergo() {
  // Set flags based on ergonomics.
  jint result = set_ergonomics_flags();  //  ★
  if (result != JNI_OK) return result;
  .....
jint Arguments::set_ergonomics_flags() {
  GCConfig::initialize();   //  ★
  set_conservative_max_heap_alignment();
  .....
share/gc/shared/gcConfig.cpp
void GCConfig::initialize() {
  assert(_arguments == NULL, "Already initialized");
  _arguments = select_gc();  //  ★
}
....
GCArguments* GCConfig::select_gc() {
  // Fail immediately if an unsupported GC is selected
  fail_if_unsupported_gc_is_selected();
  if (is_no_gc_selected()) {   //★ If the GC method is not specified
    // Try select GC ergonomically
    select_gc_ergonomically();    //★ Determine the GC method here
    .....
is_no_gc_selected
is_no_gc_selected returns true if no method is specified, false if the GC method is already specified.
share/gc/shared/gcConfig.cpp
bool GCConfig::is_no_gc_selected() {
  FOR_EACH_SUPPORTED_GC(gc) {   //  ★
    if (gc->_flag) {
      return false;
    }
  }
  return true;
}
FOR_EACH_SUPPORTED_GC is defined below.
python
#define FOR_EACH_SUPPORTED_GC(var)                                          \
  for (const SupportedGC* var = &SupportedGCs[0]; var < &SupportedGCs[ARRAY_SIZE(SupportedGCs)]; var++)
SupportedGCs lists the supported GC methods.
python
static const SupportedGC SupportedGCs[] = {
       CMSGC_ONLY_ARG(SupportedGC(UseConcMarkSweepGC, CollectedHeap::CMS,      cmsArguments,      "concurrent mark sweep gc"))
   EPSILONGC_ONLY_ARG(SupportedGC(UseEpsilonGC,       CollectedHeap::Epsilon,  epsilonArguments,  "epsilon gc"))
        G1GC_ONLY_ARG(SupportedGC(UseG1GC,            CollectedHeap::G1,       g1Arguments,       "g1 gc"))
  PARALLELGC_ONLY_ARG(SupportedGC(UseParallelGC,      CollectedHeap::Parallel, parallelArguments, "parallel gc"))
  PARALLELGC_ONLY_ARG(SupportedGC(UseParallelOldGC,   CollectedHeap::Parallel, parallelArguments, "parallel gc"))
    SERIALGC_ONLY_ARG(SupportedGC(UseSerialGC,        CollectedHeap::Serial,   serialArguments,   "serial gc"))
         ZGC_ONLY_ARG(SupportedGC(UseZGC,             CollectedHeap::Z,        zArguments,        "z gc"))
};
select_gc_ergonomically
Here, the GC method is determined depending on whether or not it is a server class machine.
python
void GCConfig::select_gc_ergonomically() {
  if (os::is_server_class_machine()) {
#if INCLUDE_G1GC
    FLAG_SET_ERGO_IF_DEFAULT(bool, UseG1GC, true);  //★ G1GC for server class machines
#elif INCLUDE_PARALLELGC
    FLAG_SET_ERGO_IF_DEFAULT(bool, UseParallelGC, true);
#elif INCLUDE_SERIALGC
    FLAG_SET_ERGO_IF_DEFAULT(bool, UseSerialGC, true);
#endif
  } else {
#if INCLUDE_SERIALGC
    FLAG_SET_ERGO_IF_DEFAULT(bool, UseSerialGC, true);  //★ SerialGC for client class machines
#endif
  }
}
is_server_class_machine
is_server_class_machine returns true (that is, server class machine) or false under the following conditions.
| conditions | Return value | 
|---|---|
| When the option NeverActAsServerClassMachine is specified | false | 
| When the option AlwaysActAsServerClassMachine is specified | true | 
| 2 or more CPUs and 2G or more of memory | true | 
| other than that | false | 
share/runtime/os.cpp
bool os::is_server_class_machine() {
  // First check for the early returns
  if (NeverActAsServerClassMachine) {  //★ If NeverActAsServerClassMachine is specified, it is regarded as not a server class machine.
    return false;
  }
  if (AlwaysActAsServerClassMachine) { //★ If AlwaysActAsServerClassMachine is specified, it is regarded as a server class machine.
    return true;
  }
  // Then actually look at the machine
  bool         result            = false;
  const unsigned int    server_processors = 2;
  const julong server_memory     = 2UL * G;
  // We seem not to get our full complement of memory.
  //     We allow some part (1/8?) of the memory to be "missing",
  //     based on the sizes of DIMMs, and maybe graphics cards.
  const julong missing_memory   = 256UL * M;
  /* Is this a server class machine? */  //★ True if 2 or more CPUs and 2G or more of memory
  if ((os::active_processor_count() >= (int)server_processors) &&
      (os::physical_memory() >= (server_memory - missing_memory))) {
    const unsigned int logical_processors =
      VM_Version::logical_processors_per_package();
    if (logical_processors > 1) {
      const unsigned int physical_packages =
        os::active_processor_count() / logical_processors;
      if (physical_packages >= server_processors) {
        result = true;
      }
    } else {
      result = true;
    }
  }
  return result;
}
        Recommended Posts