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