Pausa stop-the-world do GC no servidor Stop-the-world GC pause
ID da causa mem-gc · Responsável principal Desenvolvimento do servidor (Equipe de desenvolvimento) · Também envolvidos Infraestrutura de servidores (Equipe de infraestrutura)
Para coletar o lixo, um servidor em Java ou C# interrompe todas as threads (stop-the-world), e o servidor inteiro fica parado enquanto isso dura.
Por quê O heap enche e o GC começa → Efeito Todas as threads do jogo param durante a coleta (quanto mais dados vivos, mais demora) → Na tela Travamento para todos no servidor ao mesmo tempo, seguido de avanço rápido
Responsável principal Desenvolvimento do servidor (Equipe de desenvolvimento) · Também envolvidos Infraestrutura de servidores (Equipe de infraestrutura)
O que fazer (Equipe de desenvolvimento)
Definir explicitamente nas opções de inicialização um GC de pausas curtas (ZGC, Shenandoah ou G1 com meta de pausa menor), reduzir alocações, ajustar o tamanho do heap.
O que fazer (Equipe de infraestrutura)
Usar instâncias com memória suficiente para um heap folgado, dar aos contêineres pelo menos 2 CPUs e cerca de 1,8 GB de memória (abaixo disso, o JDK 26 e anteriores escolhem o Serial GC como padrão), monitorar o tempo de pausa do GC.
Números de referência
O Minor GC, que coleta só os objetos novos (geração young), leva de alguns a dezenas de ms. O Full GC, que coleta o heap inteiro com vários GB de dados vivos, pode passar de 1 s. O ZGC fica abaixo de 1 ms quase independentemente do tamanho do heap, e o Shenandoah também tem pausas curtas, que não crescem com o tamanho do heap.
No gráfico
Picos em intervalos regulares · Tempo de tick do servidor, tempo de pausa do GC
Onde olhar
Ativar o log do GC e sobrepor o horário e a duração de cada pausa ao gráfico de tempo de tick do servidor. No Java, as linhas Pause da opção de inicialização -Xlog:gc* (-XX:+PrintGCDetails no JDK 8 e anteriores); no .NET, a métrica de pausa do GC no dotnet-counters (dotnet.gc.pause.time a partir do .NET 9, % Time in GC since last GC no 8 e anteriores); no Go, a linha que o GODEBUG=gctrace=1 registra a cada GC
Confirma se
Os picos de tick coincidem com as pausas do GC, e a duração da pausa é parecida com a do pico. Todas as zonas e canais do servidor dão pico no mesmo instante
Descarta se
Picos de tick sem pausas longas no log do GC: outra causa, como lock, chamada síncrona ou escrita em disco. Só uma zona dá pico: GC da engine de script (mem-script-gc) ou carga daquela zona
Como verificar
Ferramentas de infra (sem precisar do código do jogo)
Saiba mais
No Java, a meta padrão de cada pausa do G1 é 200 ms, o que equivale a 4 ticks em um servidor de 20 ticks. Se o contêiner recebe menos de 2 CPUs ou menos de cerca de 1,8 GB de memória, o Java do JDK 26 e anteriores escolhe como padrão o Serial GC, que coleta com uma única thread, e as pausas ficam bem mais longas. Servidores em C# (.NET) costumam ativar o GC de servidor e o GC em segundo plano, mas as coletas das gerações 0 e 1 (Gen0/1), que guardam os objetos novos, e o Full GC com compactação continuam parando todas as threads. No Go, as pausas costumam ficar abaixo de 1 ms, mas, com muita alocação, quem pede memória precisa assumir parte do trabalho do GC, e o tick fica mais lento. Em qualquer modelo, se a alocação for mais rápida que a coleta, a thread do jogo acaba parando: o G1 passa para um Full GC, e o ZGC segura a thread que pediu memória até a coleta terminar.
Garbage-First (G1) Garbage CollectorOracle Meta de pausa padrão do G1 de 200 ms (MaxGCPauseMillis); se a memória acaba durante a coleta, passa para um Full GC, que para e compacta o heap inteiro
JEP 439: Generational ZGCOpenJDK Pausas do ZGC de no máximo 1 ms, independentes do tamanho do heap; pausas do G1 de alguns ms a alguns segundos. Se a alocação for mais rápida que a recuperação, há risco de parada de alocação (allocation stall)
Background garbage collection.NET O GC em segundo plano só se aplica às coletas da geração 2; as coletas das gerações 0 e 1 (GC em primeiro plano) param todas as threads gerenciadas
A Guide to the Go Garbage CollectorGo O GC do Go roda quase todo de forma concorrente e só tem pausas stop-the-world curtas; com muita alocação, as goroutines assumem parte do trabalho do GC (assist), o que gera atraso
JEP 271: Unified GC LoggingOpenJDK A partir do JDK 9, o log do GC foi reimplementado com o logging unificado (-Xlog); -Xlog:gc gera uma linha por GC, como o antigo -XX:+PrintGC
The java CommandOracle Tabela de conversão das opções antigas de log do GC para -Xlog: -XX:+PrintGCDetails vira -Xlog:gc*
dotnet-counters diagnostic tool.NET A partir do .NET 9, aparece como medidores do System.Runtime (dotnet.gc.pause.time e outros); no .NET 8 e anteriores, como os antigos EventCounters (% Time in GC since last GC e outros)
runtime packageGo GODEBUG=gctrace=1: uma linha por GC, com o tempo de relógio (wall clock) de cada fase, o tamanho do heap no início e no fim do GC e o heap alvo