14 pontos por GN⁺ 2025-12-30 | 13 comentários | Compartilhar no WhatsApp
  • O runtime Mono usado pelo Unity apresenta velocidade de execução significativamente mais lenta em comparação com o .NET moderno, com casos em que o mesmo código C# pode ter diferença de até 15x
  • Em código real de jogo, a execução no Unity baseado em Mono levou 100 segundos, enquanto a mesma execução em .NET levou 38 segundos, afetando fortemente a eficiência de depuração e testes
  • Mesmo no modo Release, o Mono levou 30 segundos e o .NET 12 segundos, mantendo uma diferença de desempenho de mais de 2,5x mesmo em ambiente otimizado
  • A causa está na compilação JIT ineficiente e falhas de inlining do Mono, além do excesso de cópias de memória, em contraste com as otimizações modernas do JIT CoreCLR do .NET
  • Quando o Unity concluir a modernização do .NET baseada em CoreCLR, será possível obter grandes ganhos de desempenho tanto em jogos quanto no editor, o que deve eliminar o imposto oculto de desempenho em todos os projetos Unity

Contexto do uso do Mono no Unity

  • O Unity usa o framework Mono para executar código C# desde 2006
    • Na época, o Mono era a única implementação multiplataforma de .NET, além de ser open source e permitir modificações pelo Unity
  • A partir de 2014, a Microsoft liberou o .NET Core como open source e, em 2016, lançou o .NET Core 1.0
    • Desde então, o ecossistema .NET evoluiu rapidamente com o compilador Roslyn, novo JIT e melhorias de desempenho
  • Em 2018, engenheiros do Unity afirmaram que estavam trabalhando no port de CoreCLR, esperando um ganho de desempenho de 2x a 10x em relação ao Mono
  • Porém, até o fim de 2025, ainda não é possível executar jogos com base em CoreCLR

Diferença de desempenho entre Mono e .NET

  • O código de simulação de um projeto Unity foi executado em .NET fora do Unity para comparação direta
    • Ambiente Unity/Mono: 100 segundos, ambiente .NET: 38 segundos (com base no modo Debug)
  • No modo Release, a diferença permanece: Mono em 30 segundos, .NET em 12 segundos
    • O .NET também se destaca pela otimização multithread, gerando um mapa 4K×4K em menos de 3 segundos
  • A geração ineficiente de código do Mono é a principal causa, com diferenças de velocidade de 15x até mesmo em loops simples

Comparação de assembly: Mono vs .NET

  • Comparando o assembly x64 gerado a partir do mesmo código de teste
    • O JIT do .NET move invariantes de loop para fora do loop (hoisting) e realiza apenas o mínimo necessário de operações em registradores
    • O Mono repete cópias de memória com dezenas de instruções mov e perde desempenho com inlining ineficiente
  • Tempo de execução de um loop com repetição de int.MaxValue
    • .NET: 750ms, Mono: 11.500ms, Unity Editor(Debug): 67.000ms
  • O Mono repete desnecessariamente movimentações de memória e operações de comparação dentro do loop

O significado da adoção do CoreCLR

  • O CoreCLR oferece recursos modernos como JIT de última geração, API Span<T>, otimização SIMD e suporte a instruções de hardware
    • Esses recursos podem possibilitar ganhos adicionais de desempenho acima de 2x
  • O compilador Burst do Unity gera código nativo com base em LLVM, mas tem limitações em recursos da linguagem C#
    • O JIT moderno do CoreCLR pode oferecer desempenho semelhante ao Burst com menos restrições de linguagem
  • O CoreCLR também oferece suporte a AOT (compilação antecipada), permitindo melhor tempo de inicialização e suporte a plataformas com restrições de JIT (como iOS)
    • Ainda assim, o Unity afirma que continuará mantendo o IL2CPP

Conclusão: a necessidade de modernizar o .NET no Unity

  • O Mono apresenta desempenho de execução 1,5x a mais de 3x mais lento do que o .NET moderno, funcionando como um custo oculto em todos os projetos Unity
  • Efeitos esperados com a adoção do CoreCLR
    • Melhor desempenho em runtime, builds iterativos mais rápidos, melhorias no GC, eliminação do domain reload, maior proporção de código gerenciado
  • O roadmap do Unity 6.x inclui .NET Modernization, mas ela está prevista apenas para depois de 2026
  • Quando o suporte ao CoreCLR estiver concluído, ele poderá oferecer uma revolução prática de desempenho tanto para desenvolvedores quanto para jogadores do Unity
  • No momento, as limitações do Mono continuam sendo um gargalo de desempenho em todo o ecossistema Unity

13 comentários

 
quack337 2025-12-31

Ah... então parece que o Mono ainda é baseado no legado .NET Framework...
Não é jogo, mas estou no meio da migração de um app financeiro em WinForm com umas 100 mil linhas, usando .NET 4.8 + LINQ to SQL, para .NET 10 + Entity Framework, e dá para sentir que ficou muito mais rápido. Teve até tarefa de cálculo que levava 10 segundos e caiu para 3!

 
intajon 2025-12-30

Seria bom se também adicionassem compatibilidade com NuGet (ou será que estou dizendo isso por não conhecer bem Unity?)

 
sonohoshi 2025-12-31

Não é suporte oficial, mas existe um projeto open source chamado NuGetForUnity.

 
rkttu 2025-12-30

Em teoria, pacotes NuGet voltados para .NET Standard 2.0 podem ser importados e usados também no ambiente Unity... mas, pelo visto, ainda há vários pontos inconvenientes.

https://learn.microsoft.com/ko-kr/dotnet/…

 
sonohoshi 2025-12-30

É verdade, mas sinceramente não entendo por que fizeram questão de comparar o desempenho no editor... No mínimo, poderiam ter trazido uma comparação com uma build de debug, não? Ou não, será que aí ficaria ainda menos convincente? Por outro lado, tanto IL2CPP quanto Mono parecem tecnologias igualmente ultrapassadas.

 
foriequal0 2025-12-30

Em projetos grandes, o desempenho do editor também importa, porque prejudica bastante a experiência de desenvolvimento. O editor demora para abrir, a importação de assets também é lenta, e o ciclo de depuração/testes também é lento...

 
sonohoshi 2025-12-30

Ah... claro, isso também é importante. Quando li pela primeira vez, pareceu que o autor queria discutir algo mais fundamental sobre a velocidade de execução do código. Também é verdade que, como você disse, o Unity tem um editor lento, importação lenta e, no geral, um ciclo de testes lento...

 
dunward 2026-01-05

É muito bom ver um artigo relacionado à Unity.
Li com bastante interesse.

 
mhcoma 2025-12-30

Se isso for implementado com sucesso, é provável que a otimização dos inúmeros jogos indie melhore bastante...

 
rkttu 2025-12-30

Acho que outro motivo pelo qual o Mono precisa necessariamente ser modernizado para o CoreCLR é que a Unity provavelmente não tem nem condições nem muita disposição para investir em melhorias de desempenho do Mono. Também acho que está mais do que na hora de encerrar de vez os legados da era do .NET Framework. :-D

 
rkttu 2025-12-30

E também acho que seria bom considerar que, a partir do .NET 10, o problema que eles queriam resolver no passado com o IL2CPP está sendo tratado de forma precisa, embora em outra direção de desenvolvimento, também com o Native AOT.

Claro, a limitação aqui é que não se gera código C++ editável no meio do processo, mas, no fim das contas, a produção de binários nativos sem ocorrência de Just-In-Time ficou mais madura desde o .NET 8 e chegou ainda mais amadurecida no .NET 10.

Por esse motivo, acho que continuar adiando a modernização para o CoreCLR não será uma boa escolha para a Unity. Ou talvez uma substituição completa, migrando para outra linguagem ou outra base, possa até ser mais válida!

 
sonohoshi 2025-12-30

> É improvável que a Unity tenha condições ou vontade de investir em melhorias de desempenho do Mono

Também concordo fortemente com isso...

 
GN⁺ 2025-12-30
Comentários do Hacker News
  • Como desenvolvedor profissional de jogos, normalmente não participo de discussões sobre Unity, mas este tema toca diretamente na minha área de especialização, então deixo minha opinião
    Vi algumas partes no texto que pareciam ter sido escritas por alguém com pouca experiência prática em desenvolvimento com Unity
    1. Separar a camada de simulação da camada de apresentação sempre foi uma técnica comum de otimização de desempenho (antigamente, em geral implementada em C++)
    2. A maioria dos jogos é lançada com IL2CPP, não com o backend Mono
    3. No Unity moderno, é comum usar Burst Compiler e HPC# para desempenho. O Job System ajuda bastante
    4. Fazer profiling no editor quase não faz sentido, porque ele é muito mais lento que até mesmo um build de debug
      Resumindo: o motivo de os desenvolvedores Unity estarem animados com esta atualização não é tanto ganho de desempenho, e sim acesso a recursos modernos da linguagem. E também é comum minimizar o GC em runtime ou contornar isso com memória não gerenciada e DOTS
    • Acho que você caiu demais no marketing da Unity. A Unity sempre aborda as coisas melhorando aos poucos sistemas problemáticos
      IL2CPP não passa de um gerador de código de baixa qualidade que converte .NET IL em C++, dependente de compiladores otimizadores
      Dá para ver isso em IL2CPP Internals no blog da Unity
      Burst/HPC# também seguem tendências como ECS e SoA, mas o desempenho fica abaixo de um C++ bem escrito ou de C# com CoreCLR
      Além disso, essas tecnologias são fechadas e exclusivas da Unity, então não podem ser usadas fora dela. A Unity sempre faz marketing com benchmarks comparando com o Mono lento
      No fim, a Unity também foi forçada a aceitar o CoreCLR, e quando isso acontecer vai perceber a realidade de que código C# comum é mais rápido que o código complexo que ela empilhou até aqui
    • Como autor do texto, agradeço a opinião. Nosso jogo tem uma arquitetura totalmente sem dependência de tipos da Unity ou DLLs, então é diferente de um jogo Unity típico
      Não usamos IL2CPP porque ele não é compatível com carregamento de DLL em runtime, reflexão, empacotamento de structs com FieldOffset e coisas do tipo
      Modders podem expandir funcionalidades com injeção de IL, o que no fim acelera o desenvolvimento
      Não gosto de Burst e HPC# por causa da complexidade e das limitações. A diferença de desempenho entre Mono e .NET torna isso ainda mais frustrante
      O profiling no editor também foi útil porque mostrava melhorias de desempenho em proporções parecidas com as do build real. Em vez do profiler padrão da Unity, que é impreciso, usamos um sistema de rastreamento feito por nós
      O GC continua sendo um problema. Processamento de strings e UI geram lixo a cada frame. Com CoreCLR, deve ser possível ter APIs melhores e GC móvel, reduzindo problemas de fragmentação de memória
  • A Unity é fácil de começar a usar, mas a estrutura monolítica gera uma dívida técnica enorme
    A Asset Store é excelente, mas o motor em si passa uma sensação de falta de acabamento.
    O scripting baseado em Mono é estruturalmente complexo demais para migrar para CoreCLR com facilidade
    Se a Unity quiser realmente melhorar o Core, vai precisar redesenhar o editor inteiro, como o Blender 3.x.
    Hoje ele ainda parece uma UI de 1999
    • O maior problema da Unity é abandonar recursos novos sem concluí-los.
      Incontáveis plugins e ferramentas param na fase “0.x-preview” e, 5 a 10 anos depois, já não funcionam ou ficam soterrados por assets novos
      Por isso agora eu só uso versões 1.0 ou superiores. Caso contrário, você acaba dependente de plugin abandonado e depois precisa portar tudo de novo
      Isso é ruim para a Unity, para os desenvolvedores e para os usuários
    • A Unity parece uma empresa sem direção.
      Internamente, a falha no desenvolvimento dos próprios jogos fez com que faltasse noção real de produção de jogos
      Ela apenas adiciona os recursos que pedem, sem uma visão consistente
    • WebGPU é uma camada de abstração como o Vulkan.
      Se desempenho for o mais importante, é melhor chamar Vulkan diretamente; se portabilidade for mais importante, use WebGPU
      Como a implementação varia entre navegadores, isso gera overhead, mas isso poderia ser resolvido se o WebGPU fosse oferecido no nível de driver do sistema operacional
    • Na Unity, sempre parece que você precisa encontrar uma gambiarra para fazer qualquer coisa
      Já o Godot oferece blocos de construção simples e significativos, que permitem montar o que você quiser com liberdade
    • A Unity quebra com frequência as APIs dos próprios recursos e faz com que até tutoriais deixem de funcionar
      O mesmo vale para a Asset Store: problemas de compatibilidade entre versões tornam a manutenção difícil, e a maioria vira asset abandonado
      Quando a Unity compra um asset útil, ela nem sempre o integra direito, e os concorrentes desaparecem
      Já a Unreal Engine oferece essas coisas em nível nativo do motor
  • O GC da Unity usa Boehm GC, então é muito mais lento que o .NET ou o Mono
    A Unity também não parece ter planos de adotar um GC melhor no IL2CPP
    Quando sair um editor baseado em CoreCLR, o editor pode até ficar mais rápido que o build
    Discussão relacionada: Unity CoreCLR e modernização do .NET
    • É bom que o GC melhore, mas em jogos o mais importante é manter as alocações por frame em zero
      Se o GC incremental funcionar bem, o problema de stutter também não fica tão grave
    • Com a migração para CoreCLR, a remoção do domain reload deve melhorar bastante a velocidade do editor
    • O Mono já tem GC preciso, então fico me perguntando por que usam Boehm
  • Já era uma longa jornada desde que a Unity discutiu portar o CoreCLR em 2018
    Como C# ficou muito mais rápido por padrão, a Unity precisa concentrar todos os esforços nessa transição
    Nossa equipe levou alguns meses para sair do .NET Framework 4.7.2 e ir para o .NET 6, e depois os upgrades de versões LTS ficaram na casa de horas
  • A Unity já não parece ter capacidade técnica para fazer a migração completa para CoreCLR
    Continua atrasando, e os líderes vão saindo
    Como alternativa, recomendo o motor Stride baseado em .NET 10. Como no Unity, não há overhead de fronteira
    • O progresso é lento, mas a Unity de fato está tocando a transição para CoreCLR
    • O Stride oferece apenas parte dos recursos da Unity.
      O Godot é open source, mas o suporte a C# é instável e, se não houver build para Web, ele fica inadequado para game jams
      Precisamos de uma solução sandbox de verdade com suporte a GPU
    • Não é falta de competência técnica, e sim problema de recursos e liderança
      As prioridades mudam o tempo todo, os requisitos são alterados, e o trabalho acaba sendo refeito
      Os desenvolvedores ainda são excelentes, mas falta consistência na execução
    • A Unity carrega o peso de ter que descartar ou integrar inúmeras tecnologias e add-ons adquiridos
      Um rewrite dessa escala é uma decisão de alto risco até do ponto de vista do CEO
  • Desenvolvi o sistema Circuits do Rec Room e tive a experiência de remover dependências da Unity para poder testar em CoreCLR
    Como resultado, o desempenho melhorou bastante e a manutenção do código também ficou mais fácil, graças à redução da dependência do motor
    Ao expor conceitos da Unity só onde era necessário e usar testes para impor fronteiras, percebi o valor dessa separação lógica
  • Fico me perguntando por que o autor usa Mono em vez de IL2CPP. IL2CPP é muito mais rápido, então build com Mono é coisa do passado. Se desempenho importa, IL2CPP deveria ser o primeiro passo
  • Meu sonho é instalar o .NET SDK direto em um celular Android e executar nativamente
    Com acesso root e combinado com ferramentas de rede como WireGuard ou Tailscale, seria perfeito até como servidor portátil
    Com o novo GC do .NET 10, o stutter em jogos também praticamente desapareceria
    Hoje eu faço streaming de jogos do PC principal com Sunlight + Moonlight e jogo no celular.
    Graças à tela OLED de alta taxa de atualização, o consumo de bateria também é baixo
    • A limitação de root existe por motivos de segurança. Ela dificulta o rooting para evitar infecção por portas USB em locais públicos
    • Dá para fazer algo parecido com MAUI (Xamarin).
      Não é o .NET SDK, mas o runtime do Mono vem embutido no app, então na prática a sensação é parecida
  • Fico pensando por que a Unity ainda não fez a transição completa para .NET
    A vantagem multiplataforma do Mono já desapareceu, então não entendo por que continuam mantendo hacks complexos como o IL2CPP
    • A armadilha do custo afundado pesa muito. Como já investiram pesadamente em Mono, IL2CPP, Burst etc., fica difícil mudar de direção
    • A Unity customizou o Mono profundamente, então não dá para simplesmente trocar
      Anos de modificações fora do padrão foram se acumulando, e, a menos que seja uma big tech, também não é fácil otimizar tudo de novo
  • É surpreendente que a Unity tenha começado a transição para CoreCLR em 2018 e ainda não tenha terminado
    Para um projeto desse porte, eu imaginaria que 1 a 2 anos seriam suficientes