Encontré una fuente que describe que el gc predeterminado usa cambios según los recursos disponibles. Parece que jvm usa g1gc o serial gc dependiendo del hardware y el sistema operativo.
El recopilador en serie se selecciona de forma predeterminada en ciertas configuraciones de hardware y sistema operativo
¿Alguien puede señalar una fuente más detallada sobre cuáles son los criterios específicos y cómo se aplicaría en un entorno dockerizado/kubernetes? En otras palabras:
Podría configurar las solicitudes de recursos del pod en k8s, por ejemplo. 1500 mCpu hacen que jvm use gc serial y cambiando a 2 Cpu cambie el gc predeterminado a g1gc? ¿Cambian los límites sobre cuándo se usa qué gc según la versión de jvm (11 frente a 17)?
En JDK 11 y 17, el colector Serial se utiliza cuando solo hay una CPU disponible. De lo contrario, se selecciona G1
Si limita la cantidad de CPUS disponibles para su contenedor, JVM selecciona Serial en lugar del G1 predeterminado
docker run --cpus=1 --rm -it eclipse-temurin:11 java -Xlog:gc* -version [0.004s][info][gc] Using **Serial** utiliza Serial
docker run --cpus=2 --rm -it eclipse-temurin:11 java -Xlog:gc* -version [0.008s][info][gc ] Using G1 utiliza G1
docker run --cpus=1 --rm -it eclipse-temurin:17 java -Xlog:gc* -version [0.004s][info][gc] Using Serial utiliza Serial
docker run --cpus=2 --rm -it eclipse-temurin:17 java -Xlog:gc* -version [0.007s][info][gc] Using G1 utiliza G1
En OpenJDK actual, G1 GC se elige de forma predeterminada para la "máquina de clase de servidor" o Serial GC de lo contrario. "Máquina de clase de servidor" se define como un sistema con 2 o más CPU no HT y 2 o más GiB de RAM.
El algoritmo exacto se puede encontrar en src/hotspot/share/runtime/os.cpp :
// This is the working definition of a server class machine: // >= 2 physical CPU's and >=2GB of memory, with some fuzz // because the graphics memory (?) sometimes masks physical memory. // If you want to change the definition of a server class machine // on some OS or platform, eg, >=4GB on Windows platforms, // then you'll have to parameterize this method based on that state, // as was done for logical processors here, or replicate and // specialize this method for each platform. (Or fix os to have // some inheritance structure and use subclassing. Sigh.) // If you want some platform to always or never behave as a server // class machine, change the setting of AlwaysActAsServerClassMachine // and NeverActAsServerClassMachine in globals*.hpp. bool os::is_server_class_machine() { // First check for the early returns if (NeverActAsServerClassMachine) { return false; } if (AlwaysActAsServerClassMachine) { 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? */ 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; }