Thrashing del GC (heap casi lleno) GC thrashing (heap nearly full)
ID de la causa mem-gc-thrash · Responsable principal Desarrollo de servidor (Equipo de desarrollo) · También Infraestructura de servidores (Equipo de infraestructura)
Cuando los datos vivos se acercan al límite del heap, el GC casi no encuentra nada que liberar y se repite sin parar.
Por qué Por el aumento de jugadores en un evento o por una fuga, los datos vivos llenan el heap casi hasta el límite → Efecto El GC apenas libera memoria y enseguida lanza otro Full GC; el GC se lleva la mayor parte de la CPU → En pantalla Todo el servidor alterna cámara lenta y congelamientos durante varios minutos y acaba cerrándose por falta de memoria
Horas pico de la noche, Cuando se junta mucha gente, Cuanto más tiempo lleva encendido
Responsable
Responsable principal Desarrollo de servidor (Equipo de desarrollo) · También Infraestructura de servidores (Equipo de infraestructura)
Tareas (Equipo de desarrollo)
Configurar el heap con holgura respecto a los datos vivos en el pico (normalmente el doble o más), reducir los datos que se referencian durante mucho tiempo y las fugas.
Tareas (Equipo de infraestructura)
Configurar alertas sobre el porcentaje de tiempo en GC, reiniciar cuanto antes sin intentar aguantar, usar instancias con memoria de sobra para poder ampliar el heap.
Cifras de referencia
Si el GC consume más del 10% del tiempo de ejecución, normalmente se considera una señal de alarma. Algunos GC de Java lanzan un error de falta de memoria si dedican el 98% del tiempo al GC y apenas liberan memoria.
En el gráfico
Topa con el límite · Heap justo después del GC, porcentaje de tiempo en GC
Dónde mirar
Cuánto se acerca al heap máximo el heap que queda justo después del GC y qué porcentaje del tiempo se dedica al GC. En Java, “después del GC (tamaño del heap)” en las líneas de -Xlog:gc y la frecuencia de las líneas Pause Full; en .NET, dotnet-counters (% Time in GC since last GC en .NET 8 y anteriores; incremento de dotnet.gc.pause.time desde .NET 9); en Go, el intervalo entre líneas de GODEBUG=gctrace=1
Se confirma si
Incluso justo después del GC el heap sigue cerca del máximo, los Full GC se suceden uno tras otro y el porcentaje de tiempo en GC sube mucho más de lo normal (normalmente por encima del 10%). Mientras tanto, el tick de todo el servidor se ralentiza
Se descarta si
Si después del GC queda margen en el heap pero las pausas son largas, apunta al tipo o la configuración del GC (mem-gc)
Se verifica con
Con herramientas de infraestructura (no hace falta código del juego)
Fuentes
The Parallel CollectorOracle El Parallel GC lanza OutOfMemoryError si dedica más del 98% del tiempo total al GC y recupera menos del 2% del heap
Garbage-First Garbage Collector TuningOracle Por defecto (GCTimeRatio=12), G1 dimensiona el heap para que el GC ocupe alrededor del 8% del tiempo total o menos; los Full GC causados por una ocupación del heap demasiado alta aparecen en el log como Pause Full (G1 Compaction Pause)
A Guide to the Go Garbage CollectorGo Con el valor predeterminado GOGC=100, el heap objetivo es aproximadamente el doble del heap vivo; al chocar con el límite de memoria, el GC se ejecuta sin parar (thrashing); GODEBUG=gctrace=1 imprime la traza del GC
Garbage Collector ImplementationOracle Las líneas de -Xlog:gc muestran el tipo de GC (Pause Young, Pause Full), “uso antes del GC->uso después del GC (tamaño del heap)” y el tiempo de pausa
dotnet-counters diagnostic tool.NET Desde .NET 9 se muestra como dotnet.gc.pause.time; en .NET 8 y anteriores, como % Time in GC since last GC