A Unreal Engine (UE) usa um coletor de lixo de marcação e varredura para gerenciar a memória UObject. Para aplicações de tempo quase real, coletores de lixo historicamente apresentaram uma grande desvantagem: a possibilidade de gerar travamentos na jogabilidade enquanto o coletor de lixo determina quais objetos podem ter sua memória recuperada. Na UE, esse processo é chamado de análise de acessibilidade. A UE conta com essa fase da coleta de lixo para ser concluída em um único quadro, o que interrompe temporariamente todo o processamento do UObject (em especial a jogabilidade). Quanto mais objetos a análise de acessibilidade precisar escanear, maior será a pausa, o que pode introduzir problemas visíveis na jogabilidade como resultado. Existem várias maneiras de os programadores evitarem problemas, como:
Manter orçamentos rigorosos para UObject.
Usar pools de UObject.
Desabilitar a coleta de lixo durante a jogabilidade normal.
No entanto, essas soluções alternativas tendem a aumentar a complexidade do código e os custos gerais do projeto.
Análise de acessibilidade incremental
A UE aprimora isso usando a análise de acessibilidade incremental. Os usuários agora podem dividir a fase de análise de acessibilidade do coletor de lixo em múltiplos quadros, com um limite de tempo configurável por quadro, de forma suave. A engine rastreia referências de UObject entre iterações de acessibilidade por meio das propriedades do TObjectPtr. Isso significa que qualquer atribuição a uma UPROPERTYexposta ao TObjectPtr marca imediatamente o objeto como acessível durante a coleta de lixo. Essa barreira é conhecida como barreira de gravação do coletor de lixo.
A engine já foi convertida para usar o TObjectPtr em vez de ponteiros brutos de C++ em qualquer lugar que exponha UObjects ao coletor de lixo, incluindo qualquer função AddReferencedObjects de UObject ou FGCObject. Para usar a análise de acessibilidade incremental em projetos criados com a Unreal Engine, é essencial converter todas as instâncias de UPROPERTY para usar TObjectPtr em vez de C++ bruto. Caso contrário, a coleta de lixo poderá reivindicar parte da memória dos UObjects com antecedência. Inicialmente, estamos lançando essa funcionalidade como experimental, pois ainda é possível que a fase de análise de acessibilidade exceda o limite de tempo especificado.
Como habilitar a análise de acessibilidade incremental
A análise de acessibilidade incremental pode ser habilitada com as seguintes variáveis de console quando adicionadas ao arquivo DefaultEngine.ini do projeto:
[ConsoleVariables]
gc.AllowIncrementalReachability=1 ; enables Incremental Reachability Analysis
gc.AllowIncrementalGather=1 ; enables Incremental Gather Unreachable Objects
gc.IncrementalReachabilityTimeLimit=0.002 ; sets the soft time limit to 2msVariáveis adicionais do console
Você também pode usar variáveis de console para fins de teste de estresse e depuração:
| Variável do console | Descrição | Tipo |
|---|---|---|
| Atrasa a análise de acessibilidade pelo número especificado de quadros. Usada para testar a barreira do GC. |
|
| Executa um teste após a análise de acessibilidade estar concluída para garantir que nenhum objeto acessível (válido) esteja fazendo referência a um objeto inacessível (que será destruído em breve). | 0: desabilitado, 1: habilitado |
| Continua reiniciando a coleta de lixo incremental após a anterior ter sido concluída. | 0: desabilitado, 1: habilitado |
Comparação de desempenho
A imagem a seguir é uma visualização do Unreal Insights de um gráfico de desempenho de um projeto de exemplo com a acessibilidade incremental desativada. A linha azul representa o tempo total do quadro, e a linha laranja mostra o tempo consumido pela análise de acessibilidade. O Unreal Insights traça uma linha de gráfico contínua entre eventos únicos separados por vários quadros; embora pareça que a coleta de lixo está em toda a linha do tempo, ela só é executada em um quadro por vez.
Na primeira imagem da comparação de gráfico a seguir, você pode ver um pico sempre que a coleta de lixo é executada (indicado pelos rótulos do GC na parte superior da linha do tempo).
Na segunda imagem, com a acessibilidade incremental ativada, você pode ver que os picos de latência do GC desapareceram e que a acessibilidade incremental agora está dividida em vários quadros (representado pelas barras verdes mais largas).
Limitações conhecidas
A acessibilidade incremental não é totalmente segura para threads. Em algumas circunstâncias, um objeto que está sendo manipulado em um thread de trabalho não será marcado como acessível enquanto o coletor de lixo estiver verificando o gráfico do UObject. Isso pode resultar na coleta prematura do objeto pelo coletor de lixo. Recomendamos habilitar a acessibilidade incremental apenas em compilações de thread único (por exemplo, servidores dedicados).