Melhorar o desempenho

*Este conteúdo é traduzido por IA (Beta) e pode conter erros. Para ver a página em inglês, clique aqui.

Esta página descreve problemas comuns de desempenho e as melhores práticas para mitigá-los.

Computação de scripts

Operações caras no código Luau levam mais tempo para processar e, portanto, podem impactar a taxa de quadros. A menos que esteja sendo executado em paralelo, o código Luau é executado de forma síncrona e bloqueia a thread principal até que encontre uma função que libere a thread.

Problemas comuns

  • Operações intensivas em estruturas de tabela - Operações complexas, como serialização, desserialização e clonagem profunda, incursionam em um alto custo de desempenho, especialmente em estruturas de tabela grandes. Isso é particularmente verdadeiro se essas operações forem recursivas ou envolverem iteração sobre estruturas de dados muito grandes.

  • Eventos de alta frequência - Associar operações caras a eventos baseados em quadros do RunService sem limitar a frequência significa que essas operações são repetidas a cada quadro, o que geralmente resulta em um aumento desnecessário no tempo de computação. Esses eventos incluem:

Mitigação

  • Chame o código em eventos do RunService com moderação, limitando o uso a casos onde a invocação em alta frequência é essencial (por exemplo, atualizando a câmera). Você pode executar a maioria dos outros códigos em outros eventos ou com menos frequência em um loop.
  • Divida tarefas grandes ou caras usando task.wait() para espalhar o trabalho por múltiplos quadros.
  • Identifique e otimize operações desnecessariamente caras e use multithreading para tarefas computacionais pesadas que não precisam acessar o modelo de dados.
  • Certos scripts do lado do servidor podem se beneficiar da geração de código nativo, uma simples flag que compila um script para código de máquina em vez de bytecode.

Escopos do MicroProfiler

EscopoComputação associada
RunService.PreRenderCódigo executando no evento PreRender
RunService.PreSimulationCódigo executando no evento Stepped
RunService.PostSimulationCódigo executando no evento Heartbeat
RunService.HeartbeatCódigo executando no evento Heartbeat

Para mais informações sobre a depuração de scripts usando o MicroProfiler, consulte a biblioteca debug, que inclui funções para marcar códigos específicos e aumentar ainda mais a especificidade, como debug.profilebegin e debug.profileend. Muitos métodos da API do Roblox chamados por scripts também têm suas próprias tags associadas do MicroProfiler que podem fornecer sinais úteis.

Uso de memória de scripts

Vazamentos de memória podem ocorrer quando você escreve scripts que consomem memória que a coletora de lixo não consegue liberar corretamente quando não está mais em uso. Vazamentos são especificamente abrangentes no servidor, porque eles podem estar online continuamente por muitos dias, enquanto uma sessão do cliente é muito mais curta.

Os seguintes valores de memória no Console do Desenvolvedor podem indicar um problema que precisa de mais investigação:

  • LuaHeap - Consumo alto ou crescente sugere um vazamento de memória.
  • InstanceCount - Números de instâncias consistentemente crescentes sugerem que referências a algumas instâncias em seu código não estão sendo coletadas pelo lixo.
  • PlaceScriptMemory - Fornece um detalhamento do uso de memória script por script.

Problemas comuns

  • Deixar conexões conectadas - O motor nunca coleta eventos conectados a uma instância e quaisquer valores referenciados dentro do callback conectado. Portanto, conexões ativas de eventos e código dentro das instâncias conectadas, funções conectadas e valores referenciados ficam fora do escopo da coleta de lixo da memória, mesmo depois que os eventos são disparados.

    Embora eventos sejam desconectados quando a instância a que pertencem é destruída, um erro comum é assumir que isso se aplica aos objetos Player. Após um usuário sair de um jogo, o motor não destrói automaticamente seu objeto representativo Player e modelo de personagem, então conexões ao objeto Player e instâncias sob o modelo de personagem, como CharacterAdded, ainda consomem memória se você não desconectá-las em seus scripts. Isso pode resultar em vazamentos de memória muito significativos ao longo do tempo no servidor, à medida que centenas de usuários entram e saem do jogo.

  • Tabelas - Inserir objetos em tabelas, mas não removê-los quando não são mais necessários causa consumo desnecessário de memória, especialmente para tabelas que rastreiam dados do usuário quando eles entram. Por exemplo, o seguinte exemplo de código cria uma tabela adicionando informações do usuário cada vez que um usuário entra:

    Exemplo
    local playerInfo = {}
    Players.PlayerAdded:Connect(function(player)
    playerInfo[player] = {} -- algumas informações
    end)

    Se você não remover essas entradas quando não forem mais necessárias, a tabela continua a crescer em tamanho e consome mais memória à medida que mais usuários entram na sessão. Qualquer código que itere sobre essa tabela também se torna mais computacionalmente caro à medida que a tabela cresce em tamanho.

Mitigação

Para limpar todos os valores usados para evitar vazamentos de memória:

  • Desconectar todas as conexões - Revise seu código e certifique-se de que cada conexão seja limpa através de uma das seguintes opções:

    • Desconectando manualmente usando a função Disconnect().
    • Destruindo a instância a qual o evento pertence com a função Destroy().
    • Destruindo o objeto de script ao qual a conexão remonta.
  • Remover objetos e personagens dos jogadores após a saída - Habilite Workspace.PlayerCharacterDestroyBehavior para destruir automaticamente objetos de jogadores e modelos de personagens após um usuário sair. Se preferir, você pode limpá-los manualmente:

    Exemplo de limpeza de jogador e personagem
    local Players = game:GetService("Players")
    Players.PlayerAdded:Connect(function(player)
    player.CharacterRemoving:Connect(function(character)
    task.defer(character.Destroy, character)
    end)
    end)
    Players.PlayerRemoving:Connect(function(player)
    task.defer(player.Destroy, player)
    end)

Cálculo de Física

Uma simulação excessiva de física pode ser uma causa chave de aumento do tempo de computação por quadro tanto no servidor quanto no cliente.

Problemas comuns

  • Frequência excessiva de passos de física - Por padrão, o comportamento de passo está em modo adaptativo, onde a física avança a 60 Hz, 120 Hz ou 240 Hz, dependendo da complexidade do mecanismo físico.

    Um modo fixo com precisão melhorada da física também está disponível, que força todos os conjuntos de física a avançar a 240 Hz (quatro vezes por quadro). Isso resulta em uma computação significativamente maior a cada quadro.

  • Número excessivo de objetos simulados - Quanto mais montagens 3D forem simuladas, mais tempo levará as computações físicas a cada quadro. Muitas vezes, os jogos terão objetos sendo simulados que não precisam ser ou terão mecanismos que têm mais restrições e juntas do que precisam.

  • Detecção de colisão excessivamente precisa - Partes de malha têm uma propriedade CollisionFidelity para detectar colisões que oferece uma variedade de modos com diferentes níveis de impacto de desempenho. O modo de detecção de colisão precisa para partes de malha tem o custo de desempenho mais caro e leva mais tempo para o motor calcular.

Mitigação

  • Ancorar partes que não requerem simulação - Ancore todas as partes que não precisam ser movidas pela física, como NPCs estáticos.

  • Use passos de física adaptativos - O passo adaptativo ajusta dinamicamente a taxa de cálculos físicos para mecanismos físicos, permitindo que as atualizações de física sejam feitas com menos frequência em alguns casos.

  • Reduzir a complexidade do mecanismo

    • Sempre que possível, minimize o número de restrições ou juntas de física em uma montagem.
    • Reduza a quantidade de colisão própria dentro de um mecanismo, como aplicando limites ou restrições de colisão nula para membros de ragdoll para evitar colisões entre eles.
  • Reduza o uso de fidelidade de colisão precisa para malhas

    • Para objetos pequenos ou não interativos onde os usuários raramente notariam a diferença, use fidelidade de caixa.

    • Para objetos de tamanhos pequenos a médios, use fidelidade de caixa ou casco, dependendo da forma.

    • Para objetos grandes e muito complexos, construa colisões personalizadas usando partes invisíveis sempre que possível.

    • Para objetos que não requerem colisões, desative colisões e use fidelidade de caixa ou casco, uma vez que a geometria da colisão ainda é armazenada na memória.

    • Você pode renderizar geometria de colisão para fins de depuração no Estúdio ativando Fidelidade de colisão no widget de Opções de Visualização no canto superior direito do viewport 3D.

      Alternativamente, você pode aplicar o filtro CollisionFidelity=PreciseConvexDecomposition ao Explorer, o que mostra uma contagem de todas as partes de malha com fidelidade precisa e permite que você as selecione facilmente.

    • Para um guia detalhado sobre como escolher uma opção de fidelidade de colisão que equilibre suas necessidades de precisão e desempenho, consulte Defina parâmetros de física e renderização.

Escopos do MicroProfiler

EscopoComputação associada
physicsSteppedComputação geral de física
worldStepPassos discretos de física feitos a cada quadro

Uso de memória de física

Movimento de física e detecção de colisão consomem memória. Partes de malha têm uma propriedade CollisionFidelity que determina a abordagem usada para avaliar os limites de colisão da malha.

Problema comum

Os modos de detecção de colisão padrão e precisa consomem significativamente mais memória do que os dois outros modos com formas de colisão de menor fidelidade.

Se você vê altos níveis de consumo de memória sob PhysicsParts, pode ser necessário explorar a redução da fidelidade de colisão de objetos no seu jogo.

Como mitigar

Para reduzir a memória utilizada para fidelidade de colisão:

  • Para partes que não precisam de colisões, desative suas colisões configurando BasePart.CanCollide, BasePart.CanTouch e BasePart.CanQuery como false.
  • Reduza a fidelidade das colisões usando a configuração CollisionFidelity. Box tem a menor sobrecarga de memória, e Default e Precise são geralmente mais caros.
    • É geralmente seguro definir a fidelidade de colisão de qualquer parte pequena presa como Box.
    • Para malhas grandes e muito complexas, você pode querer construir sua própria malha de colisão a partir de objetos menores com fidelidade de colisão de caixa.

Humanoides

Humanoid é uma classe que fornece uma ampla gama de funcionalidades para personagens jogáveis e não jogáveis (NPCs). Embora seja poderosa, um Humanoid vem com um custo significativo de computação.

Problemas comuns

  • Deixar todos os HumanoidStateTypes habilitados em NPCs - Há um custo de desempenho por deixar certos HumanoidStateTypes habilitados. Desative qualquer um que não seja necessário para seus NPCs. Por exemplo, a menos que seu NPC vá escalar escadas, é seguro desativar o estado Climbing.
  • Instanciar, modificar e renascer modelos com Humanoids ou esqueletonizados MeshParts com frequência
    • Isso pode ser intensivo para o motor processar, particularmente se esses modelos usam roupas em camadas. Isso também pode ser particularmente problemático em jogos onde avatares renascem frequentemente.
    • No MicroProfiler, tags longas updateInvalidatedFastClusters (acima de 4 ms) são frequentemente um sinal de que a instância/modificação de avatar está disparando invalidações excessivas.
  • Usar Humanoides em casos onde não são necessários - NPCs estáticos que não se movem geralmente não têm necessidade da classe Humanoid.
  • Tocar animações em um grande número de NPCs a partir do servidor - animações de NPC que rodam no servidor precisam ser simuladas no servidor e replicadas para o cliente. Isso pode ser uma sobrecarga desnecessária.
  • Realizar mudanças desnecessárias de tamanho e escala - Mudanças de tamanho/escala fazem o FastCluster ser reconstruído. Tente reduzir isso durante o jogo se você estiver vendo problemas de desempenho relacionados ao FastCluster. Da mesma forma, outras mudanças de propriedades também podem fazer o FastCluster ser reconstruído, então, de forma geral, reduza essas mudanças o máximo possível.

Mitigação

  • Tocar animações de NPC no cliente - Em jogos com um grande número de NPCs, considere criar o Animator no cliente e executar as animações localmente. Isso reduz a carga no servidor e a necessidade de replicação desnecessária. Também torna possíveis otimizações adicionais (como tocar animações apenas para NPCs que estão próximos ao personagem).
  • Use alternativas amigáveis ao desempenho em vez de Humanoides - Modelos de NPC não precisam necessariamente conter um objeto humanoide.
    • Para NPCs estáticos, use um simples AnimationController, pois eles não precisam se mover, mas apenas tocar animações.
    • Para NPCs móveis, considere implementar seu próprio controlador de movimento e usar um AnimationController para animações, dependendo da complexidade dos seus NPCs.
  • Desative estados humanoides não utilizados - Use Humanoid:SetStateEnabled() para habilitar apenas estados necessários para cada humanoide.
  • Agrupamento de modelos de NPC com renascimento frequente - Em vez de destruir um NPC completamente, envie o NPC para uma piscina de NPCs inativos. Dessa forma, quando um novo NPC precisar renascer, você pode simplesmente reativar um dos NPCs da piscina. Esse processo é chamado de pool, que minimiza a quantidade de vezes que personagens precisam ser instanciados.
  • Só gere NPCs quando usuários estiverem por perto - Não gere NPCs quando os usuários não estão na proximidade e elimine-os quando os usuários saírem de sua proximidade.
  • Evite fazer mudanças na hierarquia do avatar após a instância - Certas modificações na hierarquia de um avatar têm implicações de desempenho significativas. Algumas otimizações estão disponíveis:

Escopos do MicroProfiler

EscopoComputação associada
stepHumanoidControle e física do Humanoid
stepAnimationAnimação do Humanoid e animador
updateInvalidatedFastClustersAssociado à instância ou modificação de um avatar

Renderização

Uma parte significativa do tempo que o cliente gasta a cada quadro é em renderizar a cena no quadro atual. O servidor não faz nenhuma renderização, então esta seção é exclusiva para o cliente.

Chamadas de desenho

Uma chamada de desenho é um conjunto de instruções do motor para a GPU para renderizar algo. Chamadas de desenho têm uma sobrecarga significativa. Geralmente, quanto menos chamadas de desenho por quadro, menos tempo computacional é gasto na renderização de um quadro.

Você pode ver quantas chamadas de desenho estão ocorrendo atualmente com o item Estatísticas de RenderizaçãoTempos no Estúdio. Você pode visualizar as Estatísticas de Renderização no cliente pressionando ShiftF2.

Quanto mais objetos precisam ser desenhados na sua cena em um dado quadro, mais chamadas de desenho são feitas para a GPU. No entanto, o Engine Roblox utiliza um processo chamado instanciamento para colapsar malhas idênticas com as mesmas características de textura em uma única chamada de desenho. Especificamente, várias malhas com o mesmo MeshContent são tratadas em uma única chamada de desenho quando:

Outros problemas comuns

  • Densidade excessiva de objetos - Se um grande número de objetos estiver concentrado com alta densidade, renderizar essa área da cena requer mais chamadas de desenho. Se você perceber que sua taxa de quadros cai ao olhar para uma certa parte do mapa, isso pode ser um bom sinal de que a densidade de objetos nesta área está muito alta.

    Objetos como decalques, texturas e partículas não agrupam bem e introduzem chamadas de desenho adicionais. Preste atenção extra a esses tipos de objetos em uma cena. Em particular, mudanças de propriedades em ParticleEmitters podem ter um impacto dramático no desempenho.

  • Oportunidades de instanciamento perdidas - Muitas vezes, uma cena incluirá a mesma malha duplicada várias vezes, mas cada cópia da malha tem IDs diferentes de malha ou textura. Isso impede o instanciamento e pode levar a chamadas de desenho desnecessárias.

    Uma causa comum desse problema é quando uma cena inteira é importada de uma vez, em vez de ativos individuais serem importados para Roblox e, em seguida, duplicados após a importação para montar a cena.

    Mesmo um script simples como este pode ajudá-lo a identificar partes de malha com o mesmo nome que usam IDs de malha diferentes:

    for _,descendant in workspace:GetDescendants() do
    if descendant:IsA("MeshPart") then
    print(descendant.Name .. ", " .. descendant.MeshId)
    end
    end

    A saída (com Linhas de Pilha habilitadas) pode parecer algo assim. Linhas repetidas indicam reutilização da mesma malha, o que é bom. Linhas únicas não são necessariamente ruins, mas dependendo do seu esquema de nomenclatura, podem indicar malhas duplicadas no seu jogo:

    LargeRock, rbxassetid://106420009602747 (x144) -- bom
    LargeRock, rbxassetid://120109824668127
    LargeRock, rbxassetid://134460273008628
    LargeRock, rbxassetid://139288987285823
    LargeRock, rbxassetid://71302144984955
    LargeRock, rbxassetid://90621205713698
    LargeRock, rbxassetid://113160939160788
    LargeRock, rbxassetid://135944592365226 -- todas possíveis duplicatas
  • Complexidade excessiva dos objetos - Embora não tão importante quanto o número de chamadas de desenho, o número de triângulos em uma cena influencia quanto tempo um quadro levará para renderizar. Cenas com um número muito grande de malhas muito complexas são um problema comum, assim como cenas com a propriedade MeshPart.RenderFidelity configurada para Precise em muitas malhas.

  • Sombra excessiva - Lidar com sombras é um processo caro, e mapas que contêm um número alto e densidade de objetos de luz que lançam sombras (ou um número alto e densidade de pequenas partes influenciadas por sombras) podem ter problemas de desempenho.

  • Overdraw de alta transparência - Colocar objetos com transparência parcial próximos uns dos outros força o motor a renderizar os pixels sobrepostos várias vezes, o que pode prejudicar o desempenho. Para mais informações sobre como identificar e corrigir esse problema, consulte Excluir transparências em camadas.

  • Movimento desnecessário de MeshPart esqueléticos - MeshParts esqueléticos que fazem parte de um Modelo sem um Humanoid são agrupados usando FastClusters organizados espacialmente. Quando esses MeshParts se movem, eles devem ser continuamente adicionados e removidos desses clusters espaciais, forçando a reconstrução dos clusters e impactando o desempenho.

    • Uma solução altamente eficaz é incorporar um Humanoid dentro do Modelo. A presença de um Humanoid substitui o comportamento de agrupamento espacial padrão, exigindo o uso de um único e unificado FastCluster para todo o Modelo. Consequentemente, as atualizações de posição não necessitam mais de reconstruções de cluster, mitigando assim o gargalo de desempenho. Esta técnica deve ser reservada exclusivamente para MeshParts com movimento esperado, pois pode introduzir sobrecarga de memória e anular os benefícios da otimização espacial. Recomendamos sempre monitorar o desempenho do seu jogo após fazer esse tipo de alteração. Veja Dicas de desempenho do Humanoid para mais informações.
  • Demais partes em um Model - Muitas partes em um Modelo podem causar reconstruções mais frequentes devido ao potencial de que a propriedade de uma parte mude, levando a necessidade de uma reconstrução completa. Encontre o equilíbrio certo de partes em um Modelo ao usar FastCluster.

Mitigação

  • Instanciar malhas idênticas e reduzir a quantidade de malhas únicas - Se você garantir que todas as malhas idênticas tenham os mesmos IDs de ativos subjacentes, o motor pode reconhecê-las e renderizá-las em uma única chamada de desenho. Certifique-se de apenas fazer o upload de cada malha em um mapa uma vez e, em seguida, duplicá-las no Estúdio para reutilização, em vez de importar grandes mapas como um todo, o que pode fazer com que malhas idênticas tenham IDs de conteúdo separados e sejam reconhecidas como ativos únicos pelo motor. Pacotes são um mecanismo útil para reutilização de objetos.

  • Culling - Culling descreve o processo de eliminação de chamadas de desenho para objetos que não fazem parte do quadro renderizado final. Por padrão, o motor ignora chamadas de desenho para objetos fora do campo de visão da câmera (culling de frustum) e partes, malhas e terreno ocluídos por outros objetos (culling de oclusão). Em certos cenários, como ambientes internos, você pode ser capaz de implementar um sistema de sala ou portal e ocluir objetos manualmente para reduzir ainda mais as chamadas de desenho ou a carga computacional geral.

  • Reduzir nível de detalhe para modelos - Habilite streaming de instâncias e defina a propriedade LevelOfDetail dos modelos do seu mundo como SLIM para renderizar malhas SLIM otimizadas e leves à medida que a distância da câmera aumenta.

  • Reduzir nível de detalhe para avatares - Habilite streaming de instâncias e defina Workspace.EnableSLIMAvatars para renderizar avatares de plataforma como representações SLIM leves otimizadas com total suporte a animações à medida que a distância da câmera aumenta.

  • Reduzir a fidelidade de renderização - Defina MeshPart.RenderFidelity como Automatic ou Performance. Isso permite que malhas recuem para alternativas menos complexas, o que pode reduzir o número de polígonos que precisam ser desenhados.

  • Desativar a projeção de sombras em partes e objetos de luz apropriados - O motor Roblox automaticamente degrada a qualidade das sombras à medida que o nível de qualidade gráfica do cliente diminui, finalmente desativando sombras completamente em níveis de qualidade abaixo de 4. No entanto, você pode desativar seletivamente as propriedades de projeção de sombras em objetos de luz e partes para melhorar o desempenho enquanto as sombras estão habilitadas e aumentar a probabilidade de que as sombras permaneçam habilitadas. Alguns exemplos de otimizações que você pode fazer, seja no tempo de edição ou dinamicamente em tempo de execução:

    • Use a propriedade BasePart.CastShadow para desativar a projeção de sombras em partes pequenas onde as sombras provavelmente não estarão visíveis. Essa estratégia é particularmente eficaz quando aplicada a partes que estão longe da câmera do usuário.

    • Desative sombras em objetos em movimento, quando possível.

    • Desative Light.Shadows em instâncias de luz onde o objeto não precisa lançar sombras.

    • Limite a faixa e o ângulo de instâncias de luz.

    • Use menos instâncias de luz.

    • Considere desativar luzes que estão fora de uma faixa específica ou com base em cômodos para ambientes internos.

Escopos do MicroProfiler

EscopoComputação associada
Prepare and PerformRenderização geral
Perform/Scene/computeLightingPerformAtualizações de grade de luz e sombra
LightGridCPUAtualizações de grade de luz voxel
ShadowMapSystemMapeamento de sombra
Perform/Scene/UpdateViewPreparação para renderização e atualizações de partículas
Perform/Scene/RenderViewRenderização e pós-processamento

Rede e replicação

Rede e replicação descrevem o processo pelo qual os dados são enviados entre o servidor e clientes conectados. Informações são enviadas entre o cliente e o servidor a cada quadro, mas quantidades maiores de informações requerem mais tempo de computação.

Problemas comuns

  • Tráfego remoto excessivo - Enviar uma grande quantidade de dados através de objetos RemoteEvent ou RemoteFunction ou invocá-los com muita frequência pode levar a uma grande quantidade de tempo de CPU sendo gasto no processamento de pacotes de entrada a cada quadro. Erros comuns incluem:

    • Replicar dados a cada quadro que não precisam ser replicados.
    • Replicar dados com base em entradas do usuário sem qualquer mecanismo para limitá-las.
    • Despachar mais dados do que o necessário. Por exemplo, enviar todo o inventário do jogador quando ele compra um item em vez de apenas os detalhes do item comprado.
  • Criação ou remoção de árvores de instância complexas - Quando uma mudança é feita no modelo de dados no servidor, ela é replicada para clientes conectados. Isso significa que criar e destruir hierarquias de instância grandes como mapas em tempo de execução pode ser muito intensivo em rede.

    Um culpado comum aqui é os dados de animação complexos salvos por plugins do Animation Editor em rigs. Se estes não forem removidos antes que o jogo seja publicado e o modelo animado for clonado regularmente, uma grande quantidade de dados será replicada desnecessariamente.

  • TweenService do lado do servidor - Se TweenService for usado para tween um objeto do lado do servidor, a propriedade tweened é replicada para cada cliente a cada quadro. Isso não só resulta em um tween instável à medida que a latência dos clientes flutua, mas causa um tráfego de rede desnecessário.

Mitigação

Você pode empregar as seguintes táticas para reduzir a replicação desnecessária:

  • Evite enviar grandes quantidades de dados de uma só vez através de eventos remotos. Em vez disso, envie apenas dados necessários com uma frequência menor. Por exemplo, para um estado de personagem, replique-o quando mudar, em vez de a cada quadro.
  • Divida árvores de instância complexas como mapas e carregue-as em partes para distribuir o trabalho de replicação em vários quadros.
  • Limpe os metadados de animação, especialmente o diretório de animação dos rigs, após a importação.
  • Limite a replicação de instâncias desnecessárias, especialmente em casos onde o servidor não precisa ter conhecimento das instâncias sendo criadas. Isso inclui:
    • Efeitos visuais como uma explosão ou uma explosão de magia. O servidor somente precisa saber a localização para determinar o resultado, enquanto os clientes podem criar visuais localmente.
    • Modelos de visualização de itens em primeira pessoa.
    • Tween objetos no cliente em vez do servidor.

Escopos do MicroProfiler

EscopoComputação associada
ProcessPacketsProcessamento de pacotes de rede de entrada, como invocações de eventos e alterações de propriedades
Allocate Bandwidth and Run SendersEventos de saída relevantes nos servidores

Uso de memória de ativos

O mecanismo de maior impacto disponível para os criadores para melhorar o uso de memória do cliente é habilitar o streaming de instâncias.

Streaming de instâncias

O streaming de instâncias carrega seletivamente partes do modelo de dados que não são necessárias, o que pode levar a tempos de carregamento consideravelmente reduzidos e aumentar a capacidade do cliente de prevenir falhas quando passa por pressão de memória.

Se você estiver enfrentando problemas de memória e tiver o streaming de instâncias desativado, considere atualizar seu jogo para suportá-lo, particularmente se seu mundo 3D for grande. O streaming de instâncias é baseado na distância no espaço 3D, por isso mundos maiores se beneficiam mais dele.

Se o streaming de instâncias estiver habilitado, você pode aumentar a agressividade dele. Por exemplo, considere:

  • Reduzir o uso de Enum.ModelStreamingMode.Persistent sempre que possível. Você pode precisar atualizar seus scripts se estiver usando isso como uma medida de compatibilidade.
  • Reduzir o Workspace.StreamingMinRadius e o Workspace.StreamingTargetRadius.

Para mais informações sobre opções de streaming e seus benefícios, consulte propriedades de streaming.

Outros problemas comuns

  • Duplicação de ativos - Um erro comum é carregar o mesmo ativo várias vezes resultando em IDs de ativos diferentes. Isso pode levar ao mesmo conteúdo sendo carregado na memória várias vezes.

  • Volume excessivo de ativos - Mesmo quando os ativos não são idênticos, há casos em que oportunidades para reutilizar o mesmo ativo e economizar memória são perdidas.

  • Arquivos de áudio - Arquivos de áudio podem ser uma contribuição surpreendente para o uso de memória, particularmente se você carregar todos eles no cliente de uma só vez, em vez de carregar apenas o que você precisa para uma parte do jogo. Para estratégias, veja Tempos de carregamento.

  • Texturas de alta resolução - O consumo de memória gráfica para uma textura não está relacionado ao tamanho da textura no disco; o número de pixels na textura determina o uso de memória. Por exemplo, uma textura de 1024x1024 pixels consome quatro vezes a memória gráfica de uma textura de 512x512 pixels.

    Imagens carregadas no Roblox são transcodificadas para um formato fixo, então não há benefício de memória em carregar imagens em um modelo de cor associado a menos bytes por pixel. Da mesma forma, comprimir imagens antes do upload ou remover o canal alfa de imagens que não precisam dele pode diminuir o tamanho da imagem no disco, mas não melhora o uso de memória.

    À medida que um jogo é carregado, o motor automaticamente começa com texturas de qualidade mais baixa e depois aumenta a qualidade com base na memória disponível do dispositivo, distância da câmera, quantidade de espaço de tela que a textura ocupa e outros fatores. Mesmo assim, dimensionar suas texturas estrategicamente pode melhorar o uso de memória em seu jogo.

Mitigação

  • Carregue ativos apenas uma vez - Reutilize o mesmo ID de ativo entre objetos e certifique-se de que os mesmos ativos, especialmente malhas e imagens, não sejam carregados separadamente várias vezes.

  • Encontre e corrija ativos duplicados - Procure por partes de malha idênticas e texturas que foram carregadas várias vezes com IDs diferentes.

    • Embora não haja API para detectar automaticamente semelhança de ativos, você pode coletar todos os IDs de ativos de imagem no seu lugar (seja manualmente ou com um script), baixá-los e compará-los usando ferramentas de comparação externas.
    • Para partes de malha, a melhor estratégia é pegar IDs de malha únicos e organizá-los por tamanho para identificar duplicatas manualmente.
    • Em vez de usar texturas separadas para diferentes cores, carregue uma única textura e use a propriedade SurfaceAppearance.Color para aplicar vários tons a ela.
  • Importe ativos em mapas separadamente - Em vez de importar um mapa inteiro de uma vez, importe e reconstrua os ativos no mapa individualmente. O Importador não faz nenhuma deduplicação de malhas, então se você importar um grande mapa com muitos azulejos de chão separados, cada um desses azulejos seria importado como um ativo separado (mesmo que sejam duplicatas). Isso pode levar a problemas de desempenho e memória adiante, à medida que cada malha é tratada como individualmente e ocupa memória e chamadas de desenho.

  • Limite os pixels das imagens a no máximo a quantidade necessária. A menos que uma imagem ocupe uma grande quantidade de espaço físico na tela, geralmente precisa de no máximo 512x512 pixels. A maioria das imagens menores deve ser menor que 256x256 pixels.

  • Use sheets de recortes para garantir a máxima reutilização de textura em mapas 3D. Para etapas e exemplos sobre como criar sheets de recortes, consulte Criar sheets de recortes.

    Você também pode considerar usar sprite sheets para carregar muitas imagens UI menores como uma única imagem. Você pode então usar ImageLabel.ImageRectOffset e ImageLabel.ImageRectSize para exibir porções da folha.

Tempos de carregamento

Muitos jogos implementam telas de carregamento personalizadas e usam o método ContentProvider:PreloadAsync() para solicitar ativos para que imagens, sons e malhas sejam baixados em segundo plano.

A vantagem dessa abordagem é que ela permite garantir que partes importantes do seu jogo estejam totalmente carregadas sem pop-in. No entanto, um erro comum é sobreutilizar esse método para pré-carregar mais ativos do que realmente são necessários.

Um exemplo de uma má prática é carregar todo o Workspace. Embora isso possa prevenir pop-in de textura, aumenta significativamente os tempos de carregamento.

Outra prática semelhante é utilizar ContentProvider.RequestQueueSize para garantir que todos os ativos solicitados tenham terminado de carregar. No entanto, isso apresenta o mesmo problema de tempos de carregamento significativamente aumentados, além de ser um método pouco confiável devido à sua natureza flutuante.

Em vez disso, use ContentProvider:PreloadAsync() apenas em situações necessárias, que incluem:

  • Imagens na tela de carregamento.
  • Imagens importantes no menu do seu jogo, como fundos de botões e ícones.
  • Ativos importantes na área de início ou de geração.

Se você precisar carregar um grande número de ativos, recomendamos que você forneça um botão Pular Carregamento.

©2026 Roblox Corporation, Roblox, o logotipo Roblox e Powering Imagination estão entre nossas marcas registradas e não registradas nos EUA e em outros países.