ID da causa mem-gc-thrash · Responsável principal Desenvolvimento do servidor (Equipe de desenvolvimento) · Também envolvidos Infraestrutura de servidores (Equipe de infraestrutura)
Quando os dados vivos chegam perto do limite do heap, o GC roda, mas quase não tem o que recuperar, e passa a se repetir sem parar.
Por quê Mais jogadores em um evento, ou um vazamento, enchem o heap de dados vivos até perto do limite → Efeito O GC recupera pouco e logo roda outro Full GC; o GC consome a maior parte da CPU → Na tela Todos no servidor alternam entre câmera lenta e travamento por vários minutos, até o processo ser encerrado por falta de memória
Horário de pico à noite, Quando junta muita gente, Quanto mais tempo ligado
Responsável
Responsável principal Desenvolvimento do servidor (Equipe de desenvolvimento) · Também envolvidos Infraestrutura de servidores (Equipe de infraestrutura)
O que fazer (Equipe de desenvolvimento)
Dimensionar o heap com folga em relação aos dados vivos no pico (em geral, 2 vezes ou mais), reduzir dados referenciados por muito tempo e vazamentos.
O que fazer (Equipe de infraestrutura)
Criar alerta para a proporção de tempo gasto em GC, reiniciar logo sem esperar que o servidor se recupere sozinho, usar instâncias com memória de sobra para poder aumentar o heap.
Números de referência
Em geral, considera-se sinal de perigo quando o GC passa de 10% do tempo de execução. Alguns GCs do Java geram erro de falta de memória quando gastam 98% do tempo em GC e quase não recuperam nada.
No gráfico
Achata ao bater no limite · Heap logo após o GC, proporção de tempo em GC
Onde olhar
Ver o quanto o heap que sobra logo após o GC está perto do heap máximo e a proporção de tempo gasto em GC. No Java, o valor “depois do GC (tamanho do heap)” nas linhas do -Xlog:gc e a frequência das linhas Pause Full; no .NET, o dotnet-counters (% Time in GC since last GC no .NET 8 e anteriores, aumento de dotnet.gc.pause.time a partir do .NET 9); no Go, o intervalo entre as linhas do GODEBUG=gctrace=1
Confirma se
Mesmo logo após o GC, o heap continua perto do máximo, os Full GCs rodam um atrás do outro e a proporção de tempo em GC sobe bem acima do normal (em geral, mais de 10%). Enquanto isso, o tick do servidor inteiro fica mais lento
Descarta se
Heap com folga logo após o GC, mas pausas longas: tipo ou configuração do GC (mem-gc)
Como verificar
Ferramentas de infra (sem precisar do código do jogo)
Fontes
The Parallel CollectorOracle O GC paralelo lança OutOfMemoryError se gastar mais de 98% do tempo total em GC e recuperar menos de 2% do heap
Garbage-First Garbage Collector TuningOracle Por padrão (GCTimeRatio=12), o G1 dimensiona o heap para manter o tempo de GC em no máximo cerca de 8% do total; Full GCs causados por ocupação alta demais do heap aparecem no log como Pause Full (G1 Compaction Pause)
A Guide to the Go Garbage CollectorGo Com o padrão GOGC=100, o heap alvo é cerca de 2 vezes o heap vivo; perto do limite de memória, o GC roda sem parar (thrashing); GODEBUG=gctrace=1 gera o trace do GC
Garbage Collector ImplementationOracle As linhas do -Xlog:gc mostram o tipo de GC (Pause Young, Pause Full), “uso antes do GC->uso depois do GC (tamanho do heap)” e o tempo de pausa
dotnet-counters diagnostic tool.NET A partir do .NET 9, aparece como dotnet.gc.pause.time; no .NET 8 e anteriores, como % Time in GC since last GC