Lorsque la méthode GC de Java (Parallel GC, G1GC, etc.) n'est pas spécifiée par l'option, j'ai essayé de suivre le processus avec le code source JavaVM pour voir comment il est déterminé. La source provient d'OpenJDK Java11. Src / hotspot est omis dans le chemin source suivant.
Pour écrire d'abord la conclusion, si la méthode GC n'est pas spécifiée par l'option, ce sera comme suit.
conditions | Méthode GC |
---|---|
Machine de classe serveur | UseG1GC |
Machine de classe client | UseSerialGC |
Une machine de classe serveur est essentiellement une machine avec 2 processeurs ou plus et 2 Go ou plus de mémoire.
Il est appelé dans l'ordre suivant au démarrage de JavaVM.
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
Suivez chaque source à tour de rôle.
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;
...
Si les arguments java sont analysés avec Arguments :: parse et que la méthode GC est spécifiée, l'option devient true. Par exemple, -XX: + UseParallelGC définit UseParallelGC sur true. Fondamentalement, la valeur de chaque option de JVM utilise la variable avec le nom de l'option sur la 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()) { //★ Si la méthode GC n'est pas spécifiée
// Try select GC ergonomically
select_gc_ergonomically(); //★ Déterminez la méthode GC ici
.....
is_no_gc_selected
is_no_gc_selected renvoie true si aucune méthode n'est spécifiée, false si la méthode GC est déjà spécifiée.
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 est défini ci-dessous.
python
#define FOR_EACH_SUPPORTED_GC(var) \
for (const SupportedGC* var = &SupportedGCs[0]; var < &SupportedGCs[ARRAY_SIZE(SupportedGCs)]; var++)
SupportedGCs répertorie les méthodes GC prises en charge.
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
Ici, la méthode GC est déterminée selon qu'il s'agit ou non d'une machine de classe serveur.
python
void GCConfig::select_gc_ergonomically() {
if (os::is_server_class_machine()) {
#if INCLUDE_G1GC
FLAG_SET_ERGO_IF_DEFAULT(bool, UseG1GC, true); //★ G1GC pour les machines de classe serveur
#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 pour les machines de classe client
#endif
}
}
is_server_class_machine
is_server_class_machine renvoie true (c'est-à-dire machine de classe serveur) ou false dans les conditions suivantes.
conditions | Valeur de retour |
---|---|
Lorsque l'option NeverActAsServerClassMachine est spécifiée | false |
Lorsque l'option AlwaysActAsServerClassMachine est spécifiée | true |
2 processeurs ou plus et mémoire environ 2G ou plus | true |
autre que ça | false |
share/runtime/os.cpp
bool os::is_server_class_machine() {
// First check for the early returns
if (NeverActAsServerClassMachine) { //★ Si NeverActAsServerClassMachine est spécifié, il n'est pas considéré comme une machine de classe serveur.
return false;
}
if (AlwaysActAsServerClassMachine) { //★ Si AlwaysActAsServerClassMachine est spécifié, il est considéré comme une machine de classe serveur.
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? */ //★ Vrai si 2 processeurs ou plus et 2 Go ou plus de mémoire
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