O jogo inteiro para enquanto a memória usada e descartada (lixo) é recuperada. O sinal típico são engasgos em intervalos regulares.
Por quê A cada frame, strings, arrays e listas temporárias são criadas e descartadas → Efeito Quando o lixo se acumula, o GC pausa a thread principal e recupera a memória → Na tela Engasgos regulares, a intervalos de alguns a dezenas de segundos
Responsável principal Desenvolvimento do cliente (Equipe de desenvolvimento)
O que fazer (Equipe de desenvolvimento)
Reduzir alocações (evitar concatenação de strings, LINQ e captura em lambdas), usar object pool, manter o GC incremental ligado (padrão desde o Unity 2020), rodar o GC antes da hora em momentos em que uma pausa não incomoda, como telas de carregamento.
Números de referência
Em geral, de alguns ms a 100 ms por coleta; mais que isso em celulares mais fracos ou em jogos que usam muita memória (na simulação, cerca de 150–170 ms). O GC do Unity verifica o heap inteiro a cada execução, por isso demora mais quanto mais memória o jogo estiver usando.
No gráfico
Picos em intervalos regulares · Frame time, horário de execução do GC
Onde olhar
Em build de desenvolvimento, os marcadores GC.Collect e GC.Alloc no Profiler do Unity. No Unreal, stat GC e stat Hitches (registra em log os frames que passam do tempo definido em t.HitchFrameTimeThreshold)
Confirma se
Todo frame com pico tem um trecho de GC.Collect com duração parecida com a do pico, a intervalos regulares de alguns a dezenas de segundos. Onde há muita gente, o GC.Alloc por frame aumenta
Descarta se
Frames com pico sem nenhum trecho de GC: aponta para “Carregamento síncrono e compilação de shaders na thread principal” ou “Carga de renderização com muitos personagens”
Como verificar
Exige logs e métricas do servidor ou do cliente do jogo
Saiba mais
É comum em clientes que usam C#, como os feitos em Unity. Os principais culpados são trechos de código que criam a cada frame novas strings de log de combate, números de dano e textos de UI. Se o jogo só engasga onde há muita gente, existe código que gera lixo em proporção ao número de jogadores. O GC incremental divide a coleta em pequenas partes a cada frame (3 ms por padrão no Unity), mas, se o jogo gerar lixo mais rápido do que a coleta consegue recuperar, acaba parando tudo de uma vez. O Unreal Engine também tem um GC próprio, que limpa objetos de jogo que não estão mais em uso; depende da versão e da configuração da engine, mas, na configuração padrão, ele roda mais ou menos a cada 1 minuto e pode causar engasgos em intervalos de 1 minuto. Em clientes que escrevem as regras do jogo em uma linguagem de script como Lua, o GC desse script também roda à parte.
Fontes
Garbage collection modesUnity O GC incremental é o padrão e divide a coleta entre vários frames; desligado, a thread principal fica parada enquanto o heap inteiro é verificado, o que pode chegar a centenas de ms
Profiler markers referenceUnity GC.Collect: trecho em que o código do programa fica parado durante a coleta de lixo (de menos de 1 ms a centenas de ms); GC.Alloc: alocação no heap gerenciado
Stat Commands in Unreal EngineEpic Games stat GC (estatísticas da coleta de lixo), stat Hitches (registra em log os frames que passam de t.HitchFrameTimeThreshold)